loading
Generated 2025-07-25T21:58:34+09:00

All Files ( 96.8% covered at 519.33 hits/line )

396 files in total.
24391 relevant lines, 23611 lines covered and 780 lines missed. ( 96.8% )
7859 total branches, 6936 branches covered and 923 branches missed. ( 88.26% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line Branch Coverage Branches Covered branches Missed branches
lib/bcdice.rb 100.00 % 11 8 8 0 1.00 100.00 % 0 0 0
lib/bcdice/arithmetic.rb 100.00 % 22 9 9 0 785.33 100.00 % 2 2 0
lib/bcdice/arithmetic/node.rb 92.77 % 223 83 77 6 374.57 100.00 % 3 3 0
lib/bcdice/arithmetic/parser.rb 98.68 % 242 76 75 1 461.01 50.00 % 4 2 2
lib/bcdice/arithmetic_evaluator.rb 100.00 % 18 6 6 0 743.00 100.00 % 2 2 0
lib/bcdice/base.rb 95.81 % 416 191 183 8 3935.48 83.61 % 61 51 10
lib/bcdice/command/lexer.rb 96.30 % 57 27 26 1 3106.59 81.25 % 16 13 3
lib/bcdice/command/parsed.rb 97.06 % 73 34 33 1 570.91 83.33 % 12 10 2
lib/bcdice/command/parser.rb 94.93 % 570 217 206 11 634.97 89.58 % 48 43 5
lib/bcdice/common_command.rb 100.00 % 29 13 13 0 1.00 100.00 % 0 0 0
lib/bcdice/common_command/add_dice.rb 100.00 % 20 11 11 0 335.91 100.00 % 2 2 0
lib/bcdice/common_command/add_dice/node.rb 98.31 % 661 236 232 4 258.60 91.67 % 24 22 2
lib/bcdice/common_command/add_dice/parser.rb 92.74 % 497 179 166 13 242.23 58.82 % 34 20 14
lib/bcdice/common_command/add_dice/randomizer.rb 100.00 % 42 20 20 0 1249.20 100.00 % 6 6 0
lib/bcdice/common_command/barabara_dice.rb 100.00 % 18 9 9 0 162.33 100.00 % 2 2 0
lib/bcdice/common_command/barabara_dice/node.rb 100.00 % 92 46 46 0 100.83 100.00 % 8 8 0
lib/bcdice/common_command/barabara_dice/parser.rb 87.96 % 338 108 95 13 81.43 50.00 % 6 3 3
lib/bcdice/common_command/barabara_dice/result.rb 100.00 % 28 13 13 0 40.08 100.00 % 0 0 0
lib/bcdice/common_command/calc.rb 100.00 % 18 9 9 0 130.11 100.00 % 2 2 0
lib/bcdice/common_command/calc/node.rb 100.00 % 39 18 18 0 65.00 100.00 % 2 2 0
lib/bcdice/common_command/calc/parser.rb 94.25 % 273 87 82 5 66.01 50.00 % 4 2 2
lib/bcdice/common_command/choice.rb 100.00 % 228 90 90 0 46.06 97.14 % 35 34 1
lib/bcdice/common_command/d66_dice.rb 100.00 % 81 35 35 0 83.60 100.00 % 11 11 0
lib/bcdice/common_command/lexer.rb 100.00 % 47 20 20 0 5389.90 100.00 % 6 6 0
lib/bcdice/common_command/repeat.rb 100.00 % 102 51 51 0 83.67 100.00 % 16 16 0
lib/bcdice/common_command/reroll_dice.rb 100.00 % 40 12 12 0 58.00 100.00 % 2 2 0
lib/bcdice/common_command/reroll_dice/node.rb 97.80 % 198 91 89 2 86.65 91.30 % 23 21 2
lib/bcdice/common_command/reroll_dice/parser.rb 87.50 % 423 136 119 17 32.88 50.00 % 10 5 5
lib/bcdice/common_command/tally_dice.rb 100.00 % 19 9 9 0 133.89 100.00 % 2 2 0
lib/bcdice/common_command/tally_dice/node.rb 100.00 % 135 55 55 0 14.53 100.00 % 10 10 0
lib/bcdice/common_command/tally_dice/parser.rb 88.54 % 304 96 85 11 55.60 50.00 % 4 2 2
lib/bcdice/common_command/upper_dice.rb 100.00 % 48 9 9 0 58.78 100.00 % 2 2 0
lib/bcdice/common_command/upper_dice/node.rb 100.00 % 181 82 82 0 240.17 93.75 % 16 15 1
lib/bcdice/common_command/upper_dice/parser.rb 89.13 % 435 138 123 15 25.70 50.00 % 6 3 3
lib/bcdice/common_command/version.rb 100.00 % 20 10 10 0 43.60 100.00 % 2 2 0
lib/bcdice/deprecated/checker.rb 100.00 % 78 23 23 0 329.13 90.91 % 11 10 1
lib/bcdice/dice_table.rb 100.00 % 14 12 12 0 1.00 100.00 % 0 0 0
lib/bcdice/dice_table/chain_table.rb 94.12 % 35 17 16 1 37.59 75.00 % 4 3 1
lib/bcdice/dice_table/d66_grid_table.rb 100.00 % 36 16 16 0 84.00 100.00 % 0 0 0
lib/bcdice/dice_table/d66_half_grid_table.rb 100.00 % 33 10 10 0 12.20 100.00 % 0 0 0
lib/bcdice/dice_table/d66_left_range_table.rb 100.00 % 29 13 13 0 75.08 100.00 % 0 0 0
lib/bcdice/dice_table/d66_one_third_table.rb 100.00 % 34 10 10 0 5.20 100.00 % 0 0 0
lib/bcdice/dice_table/d66_parity_table.rb 100.00 % 44 19 19 0 17.42 100.00 % 2 2 0
lib/bcdice/dice_table/d66_range_table.rb 100.00 % 28 12 12 0 100.08 100.00 % 0 0 0
lib/bcdice/dice_table/d66_table.rb 100.00 % 50 22 22 0 257.82 100.00 % 5 5 0
lib/bcdice/dice_table/range_table.rb 96.34 % 291 82 79 3 294.48 81.82 % 22 18 4
lib/bcdice/dice_table/roll_result.rb 100.00 % 45 18 18 0 934.72 100.00 % 2 2 0
lib/bcdice/dice_table/sai_fic_skill_table.rb 100.00 % 90 44 44 0 137.43 100.00 % 6 6 0
lib/bcdice/dice_table/sai_fic_skill_table/category.rb 100.00 % 25 13 13 0 178.69 100.00 % 0 0 0
lib/bcdice/dice_table/sai_fic_skill_table/skill.rb 100.00 % 23 13 13 0 611.08 100.00 % 0 0 0
lib/bcdice/dice_table/table.rb 95.00 % 45 20 19 1 1074.15 50.00 % 2 1 1
lib/bcdice/enum.rb 100.00 % 17 9 9 0 1.00 100.00 % 0 0 0
lib/bcdice/format.rb 93.75 % 38 16 15 1 912.88 90.00 % 10 9 1
lib/bcdice/game_system.rb 100.00 % 292 290 290 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/AFF2e.rb 98.61 % 141 72 71 1 8.35 91.67 % 24 22 2
lib/bcdice/game_system/AceKillerGene.rb 95.00 % 55 20 19 1 12.50 66.67 % 3 2 1
lib/bcdice/game_system/Agnostos.rb 99.12 % 248 114 113 1 10.15 98.15 % 54 53 1
lib/bcdice/game_system/Ainecadette.rb 100.00 % 68 33 33 0 8.97 88.89 % 18 16 2
lib/bcdice/game_system/Aionia.rb 100.00 % 131 73 73 0 33.55 96.67 % 30 29 1
lib/bcdice/game_system/Airgetlamh.rb 97.96 % 117 49 48 1 27.86 86.67 % 15 13 2
lib/bcdice/game_system/AlchemiaStruggle.rb 100.00 % 346 62 62 0 8.24 100.00 % 8 8 0
lib/bcdice/game_system/Alsetto.rb 98.15 % 124 54 53 1 25.13 95.24 % 21 20 1
lib/bcdice/game_system/Alshard.rb 100.00 % 26 10 10 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/AlterRaise.rb 100.00 % 282 99 99 0 3.47 93.75 % 32 30 2
lib/bcdice/game_system/Amadeus.rb 100.00 % 178 69 69 0 38.55 100.00 % 20 20 0
lib/bcdice/game_system/Amadeus_Korean.rb 100.00 % 57 13 13 0 14.23 100.00 % 0 0 0
lib/bcdice/game_system/AngelGear.rb 100.00 % 128 34 34 0 7.26 100.00 % 14 14 0
lib/bcdice/game_system/AniMalus.rb 99.23 % 261 130 129 1 8.08 93.48 % 46 43 3
lib/bcdice/game_system/AnimaAnimus.rb 97.06 % 99 34 33 1 13.03 90.00 % 10 9 1
lib/bcdice/game_system/Aoharubaan.rb 100.00 % 91 44 44 0 6.16 100.00 % 14 14 0
lib/bcdice/game_system/Arianrhod.rb 100.00 % 47 22 22 0 15.50 100.00 % 8 8 0
lib/bcdice/game_system/Arianrhod_Korean.rb 100.00 % 32 12 12 0 5.33 100.00 % 0 0 0
lib/bcdice/game_system/ArknightsFan.rb 99.41 % 340 170 169 1 27.05 92.00 % 75 69 6
lib/bcdice/game_system/ArsMagica.rb 82.56 % 149 86 71 15 13.16 68.29 % 41 28 13
lib/bcdice/game_system/AssaultEngine.rb 97.96 % 91 49 48 1 7.67 90.00 % 20 18 2
lib/bcdice/game_system/Avandner.rb 97.78 % 100 45 44 1 22.49 90.91 % 11 10 1
lib/bcdice/game_system/Ayabito.rb 100.00 % 395 44 44 0 28.64 100.00 % 18 18 0
lib/bcdice/game_system/BBN.rb 96.77 % 145 62 60 2 16.08 92.00 % 25 23 2
lib/bcdice/game_system/BadLife.rb 100.00 % 410 71 71 0 45.59 100.00 % 41 41 0
lib/bcdice/game_system/Bakenokawa.rb 100.00 % 244 42 42 0 39.81 100.00 % 8 8 0
lib/bcdice/game_system/BarnaKronika.rb 100.00 % 188 98 98 0 115.29 94.12 % 34 32 2
lib/bcdice/game_system/BattleTech.rb 98.96 % 611 193 191 2 16.81 95.31 % 64 61 3
lib/bcdice/game_system/BeastBindTrinity.rb 95.90 % 354 122 117 5 23.53 91.67 % 60 55 5
lib/bcdice/game_system/BeginningIdol.rb 100.00 % 254 113 113 0 53.56 96.30 % 54 52 2
lib/bcdice/game_system/BeginningIdol2022.rb 100.00 % 184 86 86 0 13.36 100.00 % 30 30 0
lib/bcdice/game_system/BeginningIdol_Korean.rb 100.00 % 75 17 17 0 23.94 100.00 % 0 0 0
lib/bcdice/game_system/BlackJacket.rb 98.70 % 244 77 76 1 20.91 96.43 % 28 27 1
lib/bcdice/game_system/BlackJacket_Korean.rb 98.70 % 244 77 76 1 20.91 96.43 % 28 27 1
lib/bcdice/game_system/BladeOfArcana.rb 97.65 % 252 85 83 2 7.71 94.74 % 38 36 2
lib/bcdice/game_system/BlindMythos.rb 99.41 % 463 170 169 1 18.58 97.10 % 69 67 2
lib/bcdice/game_system/BloodCrusade.rb 100.00 % 395 27 27 0 9.89 100.00 % 8 8 0
lib/bcdice/game_system/BloodMoon.rb 100.00 % 254 28 28 0 8.96 90.00 % 10 9 1
lib/bcdice/game_system/Bloodorium.rb 96.67 % 68 30 29 1 9.20 87.50 % 8 7 1
lib/bcdice/game_system/CardRanker.rb 100.00 % 209 37 37 0 8.11 93.75 % 16 15 1
lib/bcdice/game_system/CastleInGray.rb 100.00 % 135 33 33 0 7.88 100.00 % 18 18 0
lib/bcdice/game_system/ChaosFlare.rb 96.25 % 187 80 77 3 5.03 90.00 % 40 36 4
lib/bcdice/game_system/CharonSanctions.rb 100.00 % 112 28 28 0 8.89 83.33 % 6 5 1
lib/bcdice/game_system/Chill.rb 97.22 % 163 108 105 3 92.22 90.63 % 32 29 3
lib/bcdice/game_system/Chill3.rb 100.00 % 52 23 23 0 5.78 92.86 % 14 13 1
lib/bcdice/game_system/CodeLayerd.rb 100.00 % 102 54 54 0 17.17 90.91 % 22 20 2
lib/bcdice/game_system/ColossalHunter.rb 99.03 % 555 103 102 1 20.90 84.38 % 32 27 5
lib/bcdice/game_system/Comes.rb 100.00 % 50 15 15 0 1.27 100.00 % 0 0 0
lib/bcdice/game_system/ConvictorDrive.rb 100.00 % 118 32 32 0 6.66 100.00 % 6 6 0
lib/bcdice/game_system/CrashWorld.rb 100.00 % 81 36 36 0 13.50 92.31 % 13 12 1
lib/bcdice/game_system/Cthulhu.rb 97.78 % 253 135 132 3 177.34 91.11 % 45 41 4
lib/bcdice/game_system/Cthulhu7th.rb 99.29 % 552 140 139 1 29.56 95.16 % 62 59 3
lib/bcdice/game_system/Cthulhu7th_ChineseTraditional.rb 99.29 % 550 140 139 1 28.52 95.16 % 62 59 3
lib/bcdice/game_system/Cthulhu7th_ChineseTraditional/full_auto.rb 99.32 % 293 148 147 1 60.22 95.00 % 60 57 3
lib/bcdice/game_system/Cthulhu7th_ChineseTraditional/rollable.rb 100.00 % 43 19 19 0 158.11 100.00 % 6 6 0
lib/bcdice/game_system/Cthulhu7th_Korean.rb 99.49 % 383 195 194 1 34.87 94.19 % 86 81 5
lib/bcdice/game_system/CthulhuTech.rb 100.00 % 256 87 87 0 61.01 86.36 % 22 19 3
lib/bcdice/game_system/Cthulhu_ChineseTraditional.rb 100.00 % 60 12 12 0 17.50 100.00 % 0 0 0
lib/bcdice/game_system/Cthulhu_English.rb 100.00 % 59 12 12 0 18.33 100.00 % 0 0 0
lib/bcdice/game_system/Cthulhu_Korean.rb 100.00 % 59 12 12 0 17.50 100.00 % 0 0 0
lib/bcdice/game_system/Cthulhu_SimplifiedChinese.rb 100.00 % 60 12 12 0 18.00 100.00 % 0 0 0
lib/bcdice/game_system/CyberpunkRed.rb 100.00 % 140 58 58 0 29.02 94.74 % 19 18 1
lib/bcdice/game_system/CyberpunkRed_Korean.rb 100.00 % 66 13 13 0 9.46 100.00 % 0 0 0
lib/bcdice/game_system/DarkBlaze.rb 91.74 % 200 109 100 9 43.25 75.93 % 54 41 13
lib/bcdice/game_system/DarkDaysDrive.rb 100.00 % 463 34 34 0 6.50 92.86 % 14 13 1
lib/bcdice/game_system/DarkSouls.rb 100.00 % 91 45 45 0 12.20 93.75 % 16 15 1
lib/bcdice/game_system/DeadlineHeroes.rb 97.76 % 584 134 131 3 18.26 92.11 % 38 35 3
lib/bcdice/game_system/DemonParasite.rb 94.23 % 515 52 49 3 37.96 82.35 % 17 14 3
lib/bcdice/game_system/DemonSpike.rb 97.73 % 89 44 43 1 8.09 90.91 % 11 10 1
lib/bcdice/game_system/DesperateRun.rb 100.00 % 163 42 42 0 19.95 100.00 % 12 12 0
lib/bcdice/game_system/DetatokoSaga.rb 98.18 % 227 110 108 2 31.19 92.68 % 41 38 3
lib/bcdice/game_system/DetatokoSaga_Korean.rb 100.00 % 42 13 13 0 7.31 100.00 % 0 0 0
lib/bcdice/game_system/DiceBot.rb 100.00 % 35 7 7 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/DiceOfTheDead.rb 100.00 % 114 46 46 0 6.11 100.00 % 3 3 0
lib/bcdice/game_system/DivineCharger.rb 100.00 % 841 63 63 0 11.29 100.00 % 12 12 0
lib/bcdice/game_system/DoubleCross.rb 100.00 % 385 123 123 0 247.66 96.97 % 33 32 1
lib/bcdice/game_system/DoubleCross_Korean.rb 100.00 % 58 20 20 0 17.60 100.00 % 0 0 0
lib/bcdice/game_system/Dracurouge.rb 100.00 % 555 132 132 0 66.52 90.63 % 32 29 3
lib/bcdice/game_system/Dracurouge_Korean.rb 100.00 % 55 13 13 0 18.23 100.00 % 0 0 0
lib/bcdice/game_system/DungeonsAndDragons.rb 100.00 % 19 7 7 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/DungeonsAndDragons5.rb 99.29 % 250 141 140 1 15.55 95.00 % 60 57 3
lib/bcdice/game_system/EarthDawn.rb 94.26 % 225 122 115 7 81.05 78.85 % 52 41 11
lib/bcdice/game_system/EarthDawn3.rb 100.00 % 275 111 111 0 38.14 89.19 % 37 33 4
lib/bcdice/game_system/EarthDawn4.rb 100.00 % 272 129 129 0 39.64 85.00 % 40 34 6
lib/bcdice/game_system/EclipsePhase.rb 100.00 % 51 26 26 0 4.92 94.44 % 18 17 1
lib/bcdice/game_system/Elric.rb 95.45 % 40 22 21 1 3.32 92.86 % 14 13 1
lib/bcdice/game_system/Elysion.rb 99.65 % 1228 285 284 1 7.85 89.04 % 73 65 8
lib/bcdice/game_system/EmbryoMachine.rb 95.24 % 228 105 100 5 40.29 77.27 % 44 34 10
lib/bcdice/game_system/Emoklore.rb 94.92 % 134 59 56 3 10.86 85.19 % 27 23 4
lib/bcdice/game_system/EndBreaker.rb 97.67 % 131 43 42 1 8.63 88.89 % 9 8 1
lib/bcdice/game_system/EtrianOdysseySRS.rb 100.00 % 26 10 10 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/FateCoreSystem.rb 98.15 % 117 54 53 1 12.11 96.00 % 25 24 1
lib/bcdice/game_system/Fiasco.rb 98.33 % 140 60 59 1 15.38 94.12 % 17 16 1
lib/bcdice/game_system/Fiasco_Korean.rb 100.00 % 34 12 12 0 4.17 100.00 % 0 0 0
lib/bcdice/game_system/FilledWith.rb 97.12 % 372 139 135 4 11.99 92.73 % 55 51 4
lib/bcdice/game_system/FinalFantasyXIV.rb 100.00 % 115 49 49 0 14.41 94.44 % 18 17 1
lib/bcdice/game_system/FinalFantasyXIV_English.rb 100.00 % 39 12 12 0 4.17 100.00 % 0 0 0
lib/bcdice/game_system/FullFace.rb 100.00 % 143 68 68 0 8.78 100.00 % 21 21 0
lib/bcdice/game_system/FullMetalPanic.rb 100.00 % 26 10 10 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/FutariSousa.rb 100.00 % 323 56 56 0 35.91 100.00 % 24 24 0
lib/bcdice/game_system/FutariSousa_Korean.rb 100.00 % 78 13 13 0 18.23 100.00 % 0 0 0
lib/bcdice/game_system/GURPS.rb 98.44 % 359 64 63 1 6.78 90.00 % 20 18 2
lib/bcdice/game_system/Garactier.rb 99.18 % 479 122 121 1 7.93 98.44 % 64 63 1
lib/bcdice/game_system/Garako.rb 98.46 % 660 65 64 1 8.20 91.67 % 24 22 2
lib/bcdice/game_system/GardenOrder.rb 98.44 % 837 64 63 1 35.42 79.31 % 29 23 6
lib/bcdice/game_system/GehennaAn.rb 95.65 % 136 69 66 3 18.93 76.92 % 26 20 6
lib/bcdice/game_system/GeishaGirlwithKatana.rb 98.11 % 120 53 52 1 9.49 93.75 % 16 15 1
lib/bcdice/game_system/GhostLive.rb 100.00 % 144 13 13 0 3.00 100.00 % 0 0 0
lib/bcdice/game_system/GoblinSlayer.rb 96.67 % 190 90 87 3 15.97 93.48 % 46 43 3
lib/bcdice/game_system/GoldenSkyStories.rb 90.91 % 77 33 30 3 2.39 50.00 % 12 6 6
lib/bcdice/game_system/Gorilla.rb 100.00 % 38 14 14 0 7.50 100.00 % 2 2 0
lib/bcdice/game_system/GranCrest.rb 100.00 % 289 35 35 0 7.74 90.00 % 10 9 1
lib/bcdice/game_system/GundamSentinel.rb 96.88 % 377 128 124 4 6.84 88.10 % 42 37 5
lib/bcdice/game_system/Gundog.rb 96.30 % 53 27 26 1 24.33 81.25 % 16 13 3
lib/bcdice/game_system/GundogRevised.rb 93.51 % 295 77 72 5 9.69 79.49 % 39 31 8
lib/bcdice/game_system/GundogZero.rb 100.00 % 261 56 56 0 101.29 82.61 % 23 19 4
lib/bcdice/game_system/GurpsFW.rb 61.58 % 2326 341 210 131 1.99 42.77 % 166 71 95
lib/bcdice/game_system/HarnMaster.rb 96.39 % 201 83 80 3 4.45 88.00 % 25 22 3
lib/bcdice/game_system/HatsuneMiku.rb 100.00 % 746 73 73 0 23.75 96.00 % 25 24 1
lib/bcdice/game_system/HeroScale.rb 99.61 % 837 516 514 2 4.94 98.63 % 146 144 2
lib/bcdice/game_system/Hieizan.rb 100.00 % 39 21 21 0 4.33 92.86 % 14 13 1
lib/bcdice/game_system/HouraiGakuen.rb 98.33 % 270 120 118 2 8.57 86.84 % 38 33 5
lib/bcdice/game_system/HunterTheReckoning5th.rb 98.67 % 159 75 74 1 33.36 97.06 % 34 33 1
lib/bcdice/game_system/HuntersMoon.rb 98.39 % 404 62 61 1 43.31 88.89 % 18 16 2
lib/bcdice/game_system/IfIfIf.rb 100.00 % 648 56 56 0 2.36 100.00 % 8 8 0
lib/bcdice/game_system/Illusio.rb 100.00 % 80 36 36 0 7.03 90.00 % 10 9 1
lib/bcdice/game_system/InfiniteBabeL.rb 100.00 % 518 10 10 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/InfiniteFantasia.rb 100.00 % 56 29 29 0 5.34 94.44 % 18 17 1
lib/bcdice/game_system/Insane.rb 100.00 % 188 61 61 0 14.15 88.24 % 17 15 2
lib/bcdice/game_system/Insane_Korean.rb 100.00 % 61 14 14 0 9.00 100.00 % 0 0 0
lib/bcdice/game_system/InvisibleLiar.rb 100.00 % 79 11 11 0 4.64 100.00 % 0 0 0
lib/bcdice/game_system/Irisbane.rb 100.00 % 154 60 60 0 20.68 96.00 % 25 24 1
lib/bcdice/game_system/IthaWenUa.rb 93.33 % 31 15 14 1 2.53 87.50 % 8 7 1
lib/bcdice/game_system/JamesBond.rb 100.00 % 45 22 22 0 5.64 92.86 % 14 13 1
lib/bcdice/game_system/JekyllAndHyde.rb 100.00 % 42 10 10 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/JuinKansen.rb 100.00 % 251 12 12 0 5.25 100.00 % 0 0 0
lib/bcdice/game_system/Kamigakari.rb 98.95 % 199 95 94 1 19.29 95.00 % 20 19 1
lib/bcdice/game_system/Kamigakari_Korean.rb 100.00 % 40 13 13 0 4.38 100.00 % 0 0 0
lib/bcdice/game_system/KamitsubakiCityUnderConstructionNarrative.rb 98.94 % 251 94 93 1 20.79 96.88 % 32 31 1
lib/bcdice/game_system/KanColle.rb 87.01 % 784 77 67 10 9.08 65.00 % 20 13 7
lib/bcdice/game_system/Karukami.rb 97.56 % 84 41 40 1 10.39 92.31 % 13 12 1
lib/bcdice/game_system/KemonoNoMori.rb 100.00 % 377 48 48 0 9.56 90.48 % 21 19 2
lib/bcdice/game_system/KillDeathBusiness.rb 97.60 % 573 250 244 6 19.84 85.71 % 77 66 11
lib/bcdice/game_system/KillDeathBusiness_Korean.rb 100.00 % 58 14 14 0 19.86 100.00 % 0 0 0
lib/bcdice/game_system/KimitoYell.rb 96.86 % 568 159 154 5 9.89 95.00 % 80 76 4
lib/bcdice/game_system/KizunaBullet.rb 100.00 % 240 79 79 0 17.28 100.00 % 18 18 0
lib/bcdice/game_system/KurayamiCrying.rb 100.00 % 188 14 14 0 3.50 100.00 % 2 2 0
lib/bcdice/game_system/Kutulu.rb 100.00 % 95 44 44 0 6.68 90.00 % 10 9 1
lib/bcdice/game_system/KyokoShinshoku.rb 98.78 % 201 82 81 1 22.34 98.00 % 50 49 1
lib/bcdice/game_system/Liminal.rb 90.91 % 136 66 60 6 3.52 80.77 % 26 21 5
lib/bcdice/game_system/LiveraDoll.rb 97.44 % 325 39 38 1 11.26 75.00 % 12 9 3
lib/bcdice/game_system/LogHorizon.rb 98.72 % 541 235 232 3 55.68 92.73 % 110 102 8
lib/bcdice/game_system/LogHorizon_Korean.rb 100.00 % 105 13 13 0 22.85 100.00 % 0 0 0
lib/bcdice/game_system/LostRecord.rb 100.00 % 29 10 10 0 1.20 100.00 % 0 0 0
lib/bcdice/game_system/LostRoyal.rb 99.03 % 239 103 102 1 18.48 96.88 % 32 31 1
lib/bcdice/game_system/MagicaLogia.rb 98.91 % 262 92 91 1 52.72 86.36 % 22 19 3
lib/bcdice/game_system/MagicaLogia_Korean.rb 100.00 % 66 14 14 0 23.00 100.00 % 0 0 0
lib/bcdice/game_system/MagicaLogia_SimplifiedChinese.rb 100.00 % 66 14 14 0 23.00 100.00 % 0 0 0
lib/bcdice/game_system/Magius.rb 98.15 % 125 54 53 1 5.93 87.50 % 16 14 2
lib/bcdice/game_system/Magius_3rdNewTokyoCity.rb 100.00 % 62 26 26 0 1.77 100.00 % 12 12 0
lib/bcdice/game_system/MamonoScramble.rb 100.00 % 98 35 35 0 7.91 100.00 % 6 6 0
lib/bcdice/game_system/MeikyuDays.rb 95.38 % 416 65 62 3 36.83 83.33 % 30 25 5
lib/bcdice/game_system/MeikyuKingdom.rb 98.86 % 466 264 261 3 65.47 90.00 % 110 99 11
lib/bcdice/game_system/MeikyuKingdomBasic.rb 67.88 % 269 137 93 44 12.66 57.78 % 45 26 19
lib/bcdice/game_system/MetalHead.rb 98.81 % 239 84 83 1 8.79 94.59 % 37 35 2
lib/bcdice/game_system/MetalHeadExtream.rb 98.03 % 917 254 249 5 12.34 92.31 % 104 96 8
lib/bcdice/game_system/MetallicGuardian.rb 100.00 % 30 10 10 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/MonotoneMuseum.rb 98.36 % 171 61 60 1 23.11 90.00 % 20 18 2
lib/bcdice/game_system/MonotoneMuseum_Korean.rb 100.00 % 44 13 13 0 7.46 100.00 % 0 0 0
lib/bcdice/game_system/NRR.rb 100.00 % 122 50 50 0 6.90 92.86 % 14 13 1
lib/bcdice/game_system/NSSQ.rb 100.00 % 180 89 89 0 7.19 92.86 % 42 39 3
lib/bcdice/game_system/Nechronica.rb 100.00 % 145 65 65 0 21.34 95.45 % 22 21 1
lib/bcdice/game_system/Nechronica_Korean.rb 100.00 % 43 13 13 0 5.15 100.00 % 0 0 0
lib/bcdice/game_system/NervWhitePaper.rb 100.00 % 129 72 72 0 2.82 93.33 % 30 28 2
lib/bcdice/game_system/NeverCloud.rb 97.73 % 620 44 43 1 41.48 95.00 % 20 19 1
lib/bcdice/game_system/NightWizard.rb 98.28 % 231 116 114 2 46.80 94.29 % 35 33 2
lib/bcdice/game_system/NightWizard3rd.rb 100.00 % 37 11 11 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/NightmareHunterDeep.rb 98.00 % 116 50 49 1 27.90 85.00 % 20 17 3
lib/bcdice/game_system/NinjaSlayer.rb 97.78 % 265 90 88 2 14.41 91.67 % 24 22 2
lib/bcdice/game_system/NinjaSlayer2.rb 97.48 % 299 119 116 3 4.59 91.11 % 45 41 4
lib/bcdice/game_system/NjslyrBattle.rb 100.00 % 51 21 21 0 4.10 90.00 % 10 9 1
lib/bcdice/game_system/NobunagasBlackCastle.rb 98.72 % 237 78 77 1 11.35 94.12 % 34 32 2
lib/bcdice/game_system/Nuekagami.rb 100.00 % 293 19 19 0 5.26 50.00 % 6 3 3
lib/bcdice/game_system/OneWayHeroics.rb 96.83 % 133 63 61 2 12.30 92.86 % 28 26 2
lib/bcdice/game_system/OracleEngine.rb 95.97 % 261 124 119 5 35.10 87.93 % 58 51 7
lib/bcdice/game_system/OrgaRain.rb 100.00 % 69 31 31 0 7.58 83.33 % 6 5 1
lib/bcdice/game_system/Oukahoushin3rd.rb 100.00 % 162 18 18 0 3.67 50.00 % 2 1 1
lib/bcdice/game_system/Paradiso.rb 61.90 % 323 168 104 64 3.10 36.63 % 101 37 64
lib/bcdice/game_system/Paranoia.rb 100.00 % 64 28 28 0 2.04 57.14 % 7 4 3
lib/bcdice/game_system/ParanoiaRebooted.rb 94.12 % 109 51 48 3 6.04 76.92 % 13 10 3
lib/bcdice/game_system/ParasiteBlood.rb 88.37 % 231 43 38 5 44.49 70.59 % 17 12 5
lib/bcdice/game_system/PastFutureParadox.rb 100.00 % 1238 110 110 0 38.26 96.88 % 32 31 1
lib/bcdice/game_system/Pathfinder.rb 100.00 % 21 8 8 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/Peekaboo.rb 100.00 % 219 23 23 0 18.26 83.33 % 6 5 1
lib/bcdice/game_system/Pendragon.rb 100.00 % 39 17 17 0 2.59 90.00 % 10 9 1
lib/bcdice/game_system/PersonaO.rb 97.30 % 86 37 36 1 4.30 90.00 % 10 9 1
lib/bcdice/game_system/PhantasmAdventure.rb 76.32 % 69 38 29 9 10.61 50.00 % 28 14 14
lib/bcdice/game_system/Postman.rb 100.00 % 185 80 80 0 12.41 90.63 % 32 29 3
lib/bcdice/game_system/PulpCthulhu.rb 97.56 % 184 41 40 1 2.68 90.00 % 10 9 1
lib/bcdice/game_system/Raisondetre.rb 96.77 % 171 93 90 3 11.84 86.36 % 44 38 6
lib/bcdice/game_system/RecordOfLodossWar.rb 96.15 % 59 26 25 1 4.31 92.86 % 14 13 1
lib/bcdice/game_system/RecordOfSteam.rb 96.20 % 149 79 76 3 7.18 87.10 % 31 27 4
lib/bcdice/game_system/Revulture.rb 100.00 % 123 53 53 0 20.13 93.10 % 29 27 2
lib/bcdice/game_system/RogueLikeHalf.rb 100.00 % 198 89 89 0 4.76 94.29 % 35 33 2
lib/bcdice/game_system/RokumonSekai2.rb 96.49 % 110 57 55 2 45.70 86.36 % 22 19 3
lib/bcdice/game_system/RoleMaster.rb 100.00 % 24 10 10 0 1.20 100.00 % 0 0 0
lib/bcdice/game_system/RuinBreakers.rb 95.45 % 296 66 63 3 5.23 86.36 % 22 19 3
lib/bcdice/game_system/RuneQuest.rb 100.00 % 47 22 22 0 15.32 100.00 % 14 14 0
lib/bcdice/game_system/RuneQuestRoleplayingInGlorantha.rb 90.67 % 173 75 68 7 38.11 80.00 % 40 32 8
lib/bcdice/game_system/RyuTuber.rb 94.12 % 268 17 16 1 3.41 75.00 % 4 3 1
lib/bcdice/game_system/Ryutama.rb 96.15 % 199 104 100 4 28.13 93.48 % 46 43 3
lib/bcdice/game_system/SRS.rb 96.23 % 296 106 102 4 58.75 89.29 % 28 25 3
lib/bcdice/game_system/SajinsenkiAGuS.rb 100.00 % 158 70 70 0 20.93 96.43 % 28 27 1
lib/bcdice/game_system/SajinsenkiAGuS2E.rb 100.00 % 285 35 35 0 8.03 75.00 % 8 6 2
lib/bcdice/game_system/SamsaraBallad.rb 98.31 % 139 59 58 1 22.47 96.43 % 28 27 1
lib/bcdice/game_system/Satasupe.rb 98.03 % 397 203 199 4 108.61 88.46 % 78 69 9
lib/bcdice/game_system/ScreamHighSchool.rb 98.25 % 128 57 56 1 9.96 80.77 % 26 21 5
lib/bcdice/game_system/Sengensyou.rb 100.00 % 59 29 29 0 4.03 100.00 % 8 8 0
lib/bcdice/game_system/SevenFortressMobius.rb 100.00 % 34 12 12 0 1.50 100.00 % 0 0 0
lib/bcdice/game_system/ShadowRun.rb 100.00 % 26 12 12 0 10.33 100.00 % 0 0 0
lib/bcdice/game_system/ShadowRun4.rb 100.00 % 49 22 22 0 29.59 100.00 % 4 4 0
lib/bcdice/game_system/ShadowRun5.rb 100.00 % 80 43 43 0 11.91 100.00 % 6 6 0
lib/bcdice/game_system/SharedFantasia.rb 100.00 % 65 31 31 0 5.16 95.00 % 20 19 1
lib/bcdice/game_system/ShinMegamiTenseiKakuseihen.rb 100.00 % 85 42 42 0 10.29 90.00 % 10 9 1
lib/bcdice/game_system/ShinkuuGakuen.rb 99.36 % 506 156 155 1 20.93 94.44 % 54 51 3
lib/bcdice/game_system/ShinobiGami.rb 100.00 % 1223 72 72 0 32.15 96.67 % 30 29 1
lib/bcdice/game_system/Shiranui.rb 100.00 % 145 58 58 0 10.21 100.00 % 19 19 0
lib/bcdice/game_system/ShoujoTenrankai.rb 100.00 % 677 31 31 0 90.16 75.00 % 8 6 2
lib/bcdice/game_system/ShuumatsuBargainWars.rb 100.00 % 203 37 37 0 4.54 100.00 % 6 6 0
lib/bcdice/game_system/ShuumatsuKikou.rb 100.00 % 298 15 15 0 4.87 100.00 % 0 0 0
lib/bcdice/game_system/Siren.rb 97.92 % 97 48 47 1 5.92 80.95 % 21 17 4
lib/bcdice/game_system/Skynauts.rb 100.00 % 285 143 143 0 30.02 93.33 % 30 28 2
lib/bcdice/game_system/SkynautsBouken.rb 100.00 % 234 108 108 0 15.19 91.67 % 36 33 3
lib/bcdice/game_system/SkynautsBouken_Korean.rb 100.00 % 57 14 14 0 4.71 100.00 % 0 0 0
lib/bcdice/game_system/StarryDolls.rb 100.00 % 636 50 50 0 22.94 100.00 % 14 14 0
lib/bcdice/game_system/SteamPunkers.rb 95.12 % 505 41 39 2 11.02 85.71 % 14 12 2
lib/bcdice/game_system/StellarKnights.rb 98.86 % 232 88 87 1 27.33 93.33 % 30 28 2
lib/bcdice/game_system/StellarKnights_Korean.rb 100.00 % 79 13 13 0 16.85 100.00 % 0 0 0
lib/bcdice/game_system/StellarLife.rb 100.00 % 387 80 80 0 20.15 96.67 % 30 29 1
lib/bcdice/game_system/StrangerOfSwordCity.rb 96.77 % 115 62 60 2 15.39 81.82 % 22 18 4
lib/bcdice/game_system/StratoShout.rb 100.00 % 79 28 28 0 8.11 83.33 % 6 5 1
lib/bcdice/game_system/StratoShout_Korean.rb 100.00 % 39 14 14 0 4.14 100.00 % 0 0 0
lib/bcdice/game_system/Strave.rb 100.00 % 223 63 63 0 3.79 93.33 % 15 14 1
lib/bcdice/game_system/SwordWorld.rb 98.83 % 387 171 169 2 4891.31 93.94 % 66 62 4
lib/bcdice/game_system/SwordWorld2_0.rb 98.15 % 158 54 53 1 76.11 94.12 % 17 16 1
lib/bcdice/game_system/SwordWorld2_0_SimplifiedChinese.rb 100.00 % 84 12 12 0 13.00 100.00 % 0 0 0
lib/bcdice/game_system/SwordWorld2_5.rb 97.44 % 160 39 38 1 19.44 83.33 % 12 10 2
lib/bcdice/game_system/SwordWorld2_5_SimplifiedChinese.rb 100.00 % 95 12 12 0 16.17 100.00 % 0 0 0
lib/bcdice/game_system/SwordWorld_SimplifiedChinese.rb 100.00 % 29 12 12 0 39.17 100.00 % 0 0 0
lib/bcdice/game_system/TalesFromTheLoop.rb 100.00 % 83 34 34 0 23.26 90.00 % 10 9 1
lib/bcdice/game_system/TenkaRyouran.rb 100.00 % 26 10 10 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/TensaiGunshiNiNaro.rb 100.00 % 262 92 92 0 37.14 100.00 % 30 30 0
lib/bcdice/game_system/TheIndieHack.rb 100.00 % 82 41 41 0 4.07 94.44 % 18 17 1
lib/bcdice/game_system/TheOneRing2nd.rb 98.42 % 406 190 187 3 47.77 95.35 % 86 82 4
lib/bcdice/game_system/TheUnofficialHollowKnightRPG.rb 94.85 % 185 97 92 5 9.70 86.11 % 36 31 5
lib/bcdice/game_system/TherapieSein.rb 100.00 % 93 40 40 0 7.45 85.71 % 14 12 2
lib/bcdice/game_system/TokumeiTenkousei.rb 100.00 % 97 42 42 0 15.86 90.91 % 11 10 1
lib/bcdice/game_system/TokyoGhostResearch.rb 65.91 % 122 44 29 15 4.89 20.00 % 10 2 8
lib/bcdice/game_system/TokyoNova.rb 100.00 % 19 7 7 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/Torg.rb 96.08 % 364 153 147 6 54.80 80.43 % 46 37 9
lib/bcdice/game_system/Torg1_5.rb 91.67 % 139 36 33 3 2.89 75.00 % 4 3 1
lib/bcdice/game_system/TorgEternity.rb 98.37 % 476 246 242 4 38.11 89.77 % 88 79 9
lib/bcdice/game_system/ToshiakiHolyGrailWar.rb 97.56 % 92 41 40 1 10.68 93.75 % 16 15 1
lib/bcdice/game_system/TrailOfCthulhu.rb 100.00 % 139 56 56 0 3.59 94.74 % 19 18 1
lib/bcdice/game_system/TrinitySeven.rb 100.00 % 363 75 75 0 14.44 95.83 % 24 23 1
lib/bcdice/game_system/TunnelsAndTrolls.rb 96.18 % 287 157 151 6 82.15 81.97 % 61 50 11
lib/bcdice/game_system/TwilightGunsmoke.rb 98.00 % 526 50 49 1 7.54 85.71 % 14 12 2
lib/bcdice/game_system/UnsungDuet.rb 100.00 % 81 26 26 0 9.88 100.00 % 2 2 0
lib/bcdice/game_system/UnsungDuet_Korean.rb 100.00 % 41 13 13 0 5.15 100.00 % 0 0 0
lib/bcdice/game_system/Utakaze.rb 100.00 % 211 94 94 0 30.37 83.33 % 36 30 6
lib/bcdice/game_system/VampireTheMasquerade5th.rb 100.00 % 187 89 89 0 87.89 100.00 % 44 44 0
lib/bcdice/game_system/Ventangle.rb 96.15 % 133 52 50 2 26.98 90.00 % 20 18 2
lib/bcdice/game_system/Ventangle_Korean.rb 96.15 % 130 52 50 2 26.98 90.00 % 20 18 2
lib/bcdice/game_system/Villaciel.rb 98.40 % 554 187 184 3 4.19 83.15 % 89 74 15
lib/bcdice/game_system/VisionConnect.rb 100.00 % 135 50 50 0 28.00 100.00 % 16 16 0
lib/bcdice/game_system/WARPS.rb 94.44 % 35 18 17 1 10.11 90.00 % 10 9 1
lib/bcdice/game_system/WaresBlade.rb 100.00 % 29 13 13 0 2.62 83.33 % 6 5 1
lib/bcdice/game_system/Warhammer.rb 95.76 % 345 118 113 5 75.78 79.59 % 49 39 10
lib/bcdice/game_system/Warhammer4.rb 96.49 % 455 114 110 4 43.52 88.71 % 62 55 7
lib/bcdice/game_system/WerewolfTheApocalypse5th.rb 98.82 % 179 85 84 1 107.29 97.50 % 40 39 1
lib/bcdice/game_system/WitchQuest.rb 100.00 % 275 58 58 0 5.36 88.89 % 9 8 1
lib/bcdice/game_system/WoW.rb 100.00 % 161 60 60 0 10.23 94.44 % 18 17 1
lib/bcdice/game_system/WorldOfDarkness.rb 100.00 % 139 68 68 0 59.38 100.00 % 29 29 0
lib/bcdice/game_system/WorldsEndFrontline.rb 100.00 % 20 8 8 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/YankeeMustDie.rb 80.88 % 192 68 55 13 6.90 61.76 % 34 21 13
lib/bcdice/game_system/YankeeYogSothoth.rb 100.00 % 435 27 27 0 6.89 83.33 % 6 5 1
lib/bcdice/game_system/YearZeroEngine.rb 95.67 % 352 208 199 9 23.95 78.38 % 74 58 16
lib/bcdice/game_system/Yggdrasill.rb 98.31 % 605 177 174 3 28.82 91.03 % 78 71 7
lib/bcdice/game_system/Yotabana.rb 100.00 % 62 11 11 0 1.09 100.00 % 0 0 0
lib/bcdice/game_system/YuMyoKishi.rb 100.00 % 141 46 46 0 12.59 100.00 % 24 24 0
lib/bcdice/game_system/ZettaiReido.rb 100.00 % 137 69 69 0 10.59 95.45 % 22 21 1
lib/bcdice/game_system/ZombiLine.rb 100.00 % 115 44 44 0 11.50 100.00 % 12 12 0
lib/bcdice/game_system/beginning_idol/accessories_table.rb 100.00 % 31 9 9 0 1.33 100.00 % 0 0 0
lib/bcdice/game_system/beginning_idol/bad_status_table.rb 100.00 % 43 23 23 0 46.43 100.00 % 8 8 0
lib/bcdice/game_system/beginning_idol/chain_d66_table.rb 100.00 % 29 13 13 0 4.31 100.00 % 2 2 0
lib/bcdice/game_system/beginning_idol/chain_table.rb 94.44 % 37 18 17 1 13.00 75.00 % 4 3 1
lib/bcdice/game_system/beginning_idol/costume_table.rb 100.00 % 37 16 16 0 19.75 100.00 % 0 0 0
lib/bcdice/game_system/beginning_idol/d6_twice_table.rb 100.00 % 36 16 16 0 9.19 100.00 % 0 0 0
lib/bcdice/game_system/beginning_idol/item_table.rb 100.00 % 51 26 26 0 43.00 100.00 % 10 10 0
lib/bcdice/game_system/beginning_idol/my_skill_name_table.rb 100.00 % 44 20 20 0 3.60 100.00 % 0 0 0
lib/bcdice/game_system/beginning_idol/random_event_table.rb 100.00 % 31 15 15 0 1.60 100.00 % 2 2 0
lib/bcdice/game_system/beginning_idol/skill_table.rb 100.00 % 63 36 36 0 4.39 100.00 % 4 4 0
lib/bcdice/game_system/beginning_idol/table.rb 100.00 % 193 50 50 0 4.90 100.00 % 6 6 0
lib/bcdice/game_system/beginning_idol/with_abnormality.rb 97.67 % 74 43 42 1 5.91 66.67 % 6 4 2
lib/bcdice/game_system/beginning_idol/work_table.rb 96.88 % 57 32 31 1 28.97 90.00 % 10 9 1
lib/bcdice/game_system/cthulhu7th/full_auto.rb 99.32 % 294 148 147 1 60.80 95.00 % 60 57 3
lib/bcdice/game_system/cthulhu7th/rollable.rb 100.00 % 43 19 19 0 160.79 100.00 % 6 6 0
lib/bcdice/game_system/cyberpunk_red/tables.rb 100.00 % 168 84 84 0 2.86 100.00 % 0 0 0
lib/bcdice/game_system/filled_with/cook_tables.rb 100.00 % 119 13 13 0 1.23 100.00 % 0 0 0
lib/bcdice/game_system/filled_with/enemy_data_tables.rb 92.86 % 322 14 13 1 3.43 50.00 % 2 1 1
lib/bcdice/game_system/filled_with/event_tables.rb 100.00 % 392 21 21 0 3.14 100.00 % 0 0 0
lib/bcdice/game_system/filled_with/lot_tables.rb 94.74 % 155 19 18 1 1.21 100.00 % 0 0 0
lib/bcdice/game_system/filled_with/tresure_tables.rb 90.91 % 179 11 10 1 3.18 50.00 % 2 1 1
lib/bcdice/game_system/kizuna_bullet/tables.rb 100.00 % 171 54 54 0 2.11 100.00 % 0 0 0
lib/bcdice/game_system/meikyu_kingdom/item_table.rb 95.51 % 385 89 85 4 7.57 95.45 % 22 21 1
lib/bcdice/game_system/meikyu_kingdom/kingdom_name_table.rb 100.00 % 91 12 12 0 1.17 100.00 % 0 0 0
lib/bcdice/game_system/meikyu_kingdom/landscape_table.rb 100.00 % 198 35 35 0 29.54 100.00 % 0 0 0
lib/bcdice/game_system/meikyu_kingdom/name_tables.rb 100.00 % 225 46 46 0 55.41 100.00 % 12 12 0
lib/bcdice/game_system/meikyu_kingdom/placename_table.rb 100.00 % 216 43 43 0 44.02 100.00 % 0 0 0
lib/bcdice/game_system/meikyu_kingdom/tables.rb 100.00 % 612 87 87 0 5.31 100.00 % 0 0 0
lib/bcdice/game_system/meikyu_kingdom/word_table.rb 100.00 % 119 15 15 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/meikyu_kingdom_basic/item_table.rb 100.00 % 382 53 53 0 5.40 100.00 % 5 5 0
lib/bcdice/game_system/meikyu_kingdom_basic/kingdom_table.rb 92.31 % 186 39 36 3 1.10 100.00 % 0 0 0
lib/bcdice/game_system/meikyu_kingdom_basic/name_table.rb 84.00 % 419 75 63 12 1.33 70.00 % 20 14 6
lib/bcdice/game_system/meikyu_kingdom_basic/table.rb 100.00 % 914 4 4 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/meikyu_kingdom_basic/word_table.rb 100.00 % 123 15 15 0 1.00 100.00 % 0 0 0
lib/bcdice/game_system/one_way_heroics/dungeon_table.rb 95.24 % 69 21 20 1 2.81 75.00 % 4 3 1
lib/bcdice/game_system/one_way_heroics/random_event_table.rb 87.30 % 168 63 55 8 4.13 66.67 % 18 12 6
lib/bcdice/game_system/one_way_heroics/tables.rb 100.00 % 670 29 29 0 5.07 100.00 % 0 0 0
lib/bcdice/game_system/satasupe/tables.rb 40.00 % 723 30 12 18 0.63 100.00 % 0 0 0
lib/bcdice/game_system/sword_world/rating_lexer.rb 94.44 % 48 18 17 1 986.39 75.00 % 8 6 2
lib/bcdice/game_system/sword_world/rating_options.rb 100.00 % 53 20 20 0 13.75 100.00 % 0 0 0
lib/bcdice/game_system/sword_world/rating_parsed.rb 100.00 % 108 55 55 0 358.69 100.00 % 22 22 0
lib/bcdice/game_system/sword_world/rating_parser.rb 94.42 % 549 215 203 12 131.81 80.00 % 60 48 12
lib/bcdice/game_system/sword_world/transcendent_test.rb 100.00 % 128 53 53 0 61.62 100.00 % 17 17 0
lib/bcdice/loader.rb 85.71 % 42 14 12 2 553195.57 50.00 % 2 1 1
lib/bcdice/normalize.rb 80.00 % 40 15 12 3 280.87 77.78 % 9 7 2
lib/bcdice/preprocessor.rb 100.00 % 66 28 28 0 9071.82 100.00 % 2 2 0
lib/bcdice/randomizer.rb 100.00 % 151 57 57 0 25318.89 100.00 % 13 13 0
lib/bcdice/result.rb 100.00 % 113 47 47 0 5350.74 100.00 % 0 0 0
lib/bcdice/translate.rb 100.00 % 13 4 4 0 1241.75 100.00 % 0 0 0
lib/bcdice/user_defined_dice_table.rb 92.11 % 166 76 70 6 17.33 77.78 % 27 21 6

lib/bcdice.rb

100.0% lines covered

100.0% branches covered

8 relevant lines. 8 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/version"
  3. 1 require "bcdice/arithmetic"
  4. 1 require "bcdice/arithmetic_evaluator"
  5. 1 require "bcdice/base"
  6. 1 require "bcdice/loader"
  7. 1 require "bcdice/game_system/DiceBot"
  8. 1 require "bcdice/common_command"
  9. 1 require "bcdice/preprocessor"

lib/bcdice/arithmetic.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/arithmetic/node"
  3. 1 require "bcdice/arithmetic/parser"
  4. 1 module BCDice
  5. 1 module Arithmetic
  6. 1 class << self
  7. # 四則演算を評価する
  8. #
  9. # @param source [String]
  10. # @param round_type [Symbol]
  11. # @return [Integer, nil] パースできない式やゼロ除算が発生した場合にはnilを返す
  12. 1 def eval(source, round_type)
  13. 3530 node = Parser.parse(source)
  14. 3530 then: 3054 else: 476 node&.eval(round_type)
  15. rescue ZeroDivisionError
  16. 2 nil
  17. end
  18. end
  19. end
  20. end

lib/bcdice/arithmetic/node.rb

92.77% lines covered

100.0% branches covered

83 relevant lines. 77 lines covered and 6 lines missed.
3 total branches, 3 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module Arithmetic
  4. 1 module Node
  5. 1 class BinaryOp
  6. 1 def initialize(lhs, op, rhs)
  7. 1355 @lhs = lhs
  8. 1355 @op = op
  9. 1355 @rhs = rhs
  10. end
  11. 1 def eval(round_type)
  12. 1190 l = @lhs.eval(round_type)
  13. 1189 r = @rhs.eval(round_type)
  14. 1186 l.send(@op, r)
  15. end
  16. # @return [String] メッセージへの出力
  17. 1 def output
  18. 77 "#{@lhs.output}#{@op}#{@rhs.output}"
  19. end
  20. # @return [String] ノードのS式
  21. 1 def s_exp
  22. "(#{op_for_s_exp} #{@lhs.s_exp} #{@rhs.s_exp})"
  23. end
  24. # @return [String] S式で使う演算子の表現
  25. 1 def op_for_s_exp
  26. @op
  27. end
  28. end
  29. # 除算ノードの基底クラス
  30. #
  31. # 定数 +ROUNDING_METHOD+ で端数処理方法を示す記号
  32. # ( +'U'+, +'R'+, +''+ ) を定義すること。
  33. # また、除算および端数処理を行う +divide_and_round+ メソッドを実装すること。
  34. 1 class DivideBase < BinaryOp
  35. # ノードを初期化する
  36. # @param [Object] lhs 左のオペランドのノード
  37. # @param [Object] rhs 右のオペランドのノード
  38. 1 def initialize(lhs, rhs)
  39. 126 super(lhs, :/, rhs)
  40. end
  41. 1 def eval(round_type)
  42. 114 l = @lhs.eval(round_type)
  43. 114 r = @rhs.eval(round_type)
  44. 114 divide_and_round(l, r, round_type)
  45. end
  46. # メッセージへの出力を返す
  47. #
  48. # 通常の結果の末尾に、端数処理方法を示す記号を付加する。
  49. #
  50. # @return [String]
  51. 1 def output
  52. 31 "#{super}#{rounding_method}"
  53. end
  54. 1 private
  55. # 端数処理方法を示す記号を返す
  56. # @return [String]
  57. 1 def rounding_method
  58. 31 self.class::ROUNDING_METHOD
  59. end
  60. # S式で使う演算子の表現を返す
  61. # @return [String]
  62. 1 def op_for_s_exp
  63. "#{@op}#{rounding_method}"
  64. end
  65. # 除算および端数処理を行う
  66. # @param [Integer] _dividend 被除数
  67. # @param [Integer] _divisor 除数(0以外)
  68. # @param [Symbol] _round_type ゲームシステムの端数処理設定
  69. # @return [Integer]
  70. 1 def divide_and_round(_dividend, _divisor, _round_type)
  71. raise NotImplementedError
  72. end
  73. end
  74. # 除算(端数処理はゲームシステム依存)のノード
  75. 1 class DivideWithGameSystemDefault < DivideBase
  76. # 端数処理方法を示す記号
  77. 1 ROUNDING_METHOD = ""
  78. 1 private
  79. # 除算および端数処理を行う
  80. # @param [Integer] dividend 被除数
  81. # @param [Integer] divisor 除数(0以外)
  82. # @param [Symbol] round_type ゲームシステムの端数処理設定
  83. # @return [Integer]
  84. 1 def divide_and_round(dividend, divisor, round_type)
  85. 96 case round_type
  86. when: 9 when RoundType::CEIL
  87. 9 (dividend.to_f / divisor).ceil
  88. when: 8 when RoundType::ROUND
  89. 8 (dividend.to_f / divisor).round
  90. else: 79 else # RoundType::FLOOR
  91. 79 dividend / divisor
  92. end
  93. end
  94. end
  95. # 除算(切り上げ)のノード
  96. 1 class DivideWithCeil < DivideBase
  97. # 端数処理方法を示す記号
  98. 1 ROUNDING_METHOD = "C"
  99. 1 private
  100. # 除算および端数処理を行う
  101. # @param [Integer] dividend 被除数
  102. # @param [Integer] divisor 除数(0以外)
  103. # @param [Symbol] _round_type ゲームシステムの端数処理設定
  104. # @return [Integer]
  105. 1 def divide_and_round(dividend, divisor, _round_type)
  106. 12 (dividend.to_f / divisor).ceil
  107. end
  108. end
  109. # 除算(四捨五入)のノード
  110. 1 class DivideWithRound < DivideBase
  111. # 端数処理方法を示す記号
  112. 1 ROUNDING_METHOD = "R"
  113. 1 private
  114. # 除算および端数処理を行う
  115. # @param [Integer] dividend 被除数
  116. # @param [Integer] divisor 除数(0以外)
  117. # @param [Symbol] _round_type ゲームシステムの端数処理設定
  118. # @return [Integer]
  119. 1 def divide_and_round(dividend, divisor, _round_type)
  120. 3 (dividend.to_f / divisor).round
  121. end
  122. end
  123. # 除算(切り捨て)のノード
  124. 1 class DivideWithFloor < DivideBase
  125. # 端数処理方法を示す記号
  126. 1 ROUNDING_METHOD = "F"
  127. 1 private
  128. # 除算および端数処理を行う
  129. # @param [Integer] dividend 被除数
  130. # @param [Integer] divisor 除数(0以外)
  131. # @param [Symbol] _round_type ゲームシステムの端数処理設定
  132. # @return [Integer]
  133. 1 def divide_and_round(dividend, divisor, _round_type)
  134. 3 dividend / divisor
  135. end
  136. end
  137. 1 class Negative
  138. 1 def initialize(body)
  139. 494 @body = body
  140. end
  141. 1 def eval(round_type)
  142. 494 -@body.eval(round_type)
  143. end
  144. # @return [String] メッセージへの出力
  145. 1 def output
  146. 24 "-#{@body.output}"
  147. end
  148. 1 def s_exp
  149. "(- #{@body.s_exp})"
  150. end
  151. end
  152. # カッコで式をまとめるノード
  153. 1 class Parenthesis
  154. # @param expr [Object] カッコ内のノード
  155. 1 def initialize(expr)
  156. 46 @expr = expr
  157. end
  158. # @param round_type [Symbol] 端数処理方法
  159. # @return [Integer] 評価結果
  160. 1 def eval(round_type)
  161. 46 @expr.eval(round_type)
  162. end
  163. # @return [String] メッセージへの出力
  164. 1 def output
  165. 46 "(#{@expr.output})"
  166. end
  167. # @return [String] S式
  168. 1 def s_exp
  169. "(Parenthesis #{@expr.s_exp})"
  170. end
  171. end
  172. 1 class Number
  173. 1 def initialize(value)
  174. 10901 @value = value
  175. end
  176. 1 def eval(_round_type)
  177. 10321 @value
  178. end
  179. # @return [String] メッセージへの出力
  180. 1 def output
  181. 222 @value.to_s
  182. end
  183. 1 alias s_exp output
  184. end
  185. end
  186. end
  187. end

lib/bcdice/arithmetic/parser.rb

98.68% lines covered

50.0% branches covered

76 relevant lines. 75 lines covered and 1 lines missed.
4 total branches, 2 branches covered and 2 branches missed.
    
  1. #
  2. # DO NOT MODIFY!!!!
  3. # This file is automatically generated by Racc 1.7.3
  4. # from Racc grammar file "parser.y".
  5. #
  6. 1 require 'racc/parser.rb'
  7. 1 require "bcdice/common_command/lexer"
  8. 1 require "bcdice/arithmetic/node"
  9. 1 module BCDice
  10. 1 module Arithmetic
  11. 1 class Parser < Racc::Parser
  12. 1 def self.parse(source)
  13. 3530 new.parse(source)
  14. end
  15. 1 def parse(source)
  16. 3530 @lexer = BCDice::CommonCommand::Lexer.new(source)
  17. 3530 do_parse()
  18. rescue ParseError
  19. 476 nil
  20. end
  21. 1 private
  22. 1 def next_token
  23. 10638 @lexer.next_token
  24. end
  25. ##### State transition tables begin ###
  26. 1 racc_action_table = [
  27. 8, 17, 8, 12, 13, 4, 5, 4, 5, 7,
  28. 8, 7, 8, 12, 13, 4, 5, 4, 5, 7,
  29. 8, 7, 8, 12, 13, 4, 5, 4, 5, 7,
  30. 8, 7, 8, nil, nil, 4, 5, 4, 5, 7,
  31. 9, 7, nil, nil, 10, 11, nil, 10, 11, 22,
  32. 26, 24, 25, 27 ]
  33. 1 racc_action_check = [
  34. 0, 9, 4, 2, 2, 0, 0, 4, 4, 0,
  35. 5, 4, 7, 18, 18, 5, 5, 7, 7, 5,
  36. 10, 7, 11, 19, 19, 10, 10, 11, 11, 10,
  37. 12, 11, 13, nil, nil, 12, 12, 13, 13, 12,
  38. 1, 13, nil, nil, 16, 16, nil, 1, 1, 16,
  39. 21, 21, 21, 21 ]
  40. 1 racc_action_pointer = [
  41. -2, 40, -6, nil, 0, 8, nil, 10, nil, 1,
  42. 18, 20, 28, 30, nil, nil, 37, nil, 4, 14,
  43. nil, 47, nil, nil, nil, nil, nil, nil ]
  44. 1 racc_action_default = [
  45. -17, -17, -3, -6, -17, -17, -14, -17, -16, -17,
  46. -17, -17, -17, -17, -12, -13, -17, 28, -1, -2,
  47. -4, -7, -15, -5, -8, -9, -10, -11 ]
  48. 1 racc_goto_table = [
  49. 14, 15, 23, 1, 18, 19, nil, nil, 20, 21,
  50. 16 ]
  51. 1 racc_goto_check = [
  52. 3, 3, 4, 1, 2, 2, nil, nil, 3, 3,
  53. 1 ]
  54. 1 racc_goto_pointer = [
  55. nil, 3, -6, -4, -19, nil ]
  56. 1 racc_goto_default = [
  57. nil, nil, 2, 3, nil, 6 ]
  58. 1 racc_reduce_table = [
  59. 0, 0, :racc_error,
  60. 3, 14, :_reduce_1,
  61. 3, 14, :_reduce_2,
  62. 1, 14, :_reduce_none,
  63. 3, 15, :_reduce_4,
  64. 4, 15, :_reduce_5,
  65. 1, 15, :_reduce_none,
  66. 0, 17, :_reduce_7,
  67. 1, 17, :_reduce_8,
  68. 1, 17, :_reduce_9,
  69. 1, 17, :_reduce_10,
  70. 1, 17, :_reduce_11,
  71. 2, 16, :_reduce_12,
  72. 2, 16, :_reduce_13,
  73. 1, 16, :_reduce_none,
  74. 3, 18, :_reduce_15,
  75. 1, 18, :_reduce_16 ]
  76. 1 racc_reduce_n = 17
  77. 1 racc_shift_n = 28
  78. 1 racc_token_table = {
  79. false => 0,
  80. :error => 1,
  81. :NUMBER => 2,
  82. :R => 3,
  83. :U => 4,
  84. :C => 5,
  85. :F => 6,
  86. :PLUS => 7,
  87. :MINUS => 8,
  88. :ASTERISK => 9,
  89. :SLASH => 10,
  90. :PARENL => 11,
  91. :PARENR => 12 }
  92. 1 racc_nt_base = 13
  93. 1 racc_use_result_var = true
  94. Racc_arg = [
  95. 1 racc_action_table,
  96. racc_action_check,
  97. racc_action_default,
  98. racc_action_pointer,
  99. racc_goto_table,
  100. racc_goto_check,
  101. racc_goto_default,
  102. racc_goto_pointer,
  103. racc_nt_base,
  104. racc_reduce_table,
  105. racc_token_table,
  106. racc_shift_n,
  107. racc_reduce_n,
  108. racc_use_result_var ]
  109. 1 then: 1 else: 0 Ractor.make_shareable(Racc_arg) if defined?(Ractor)
  110. 1 Racc_token_to_s_table = [
  111. "$end",
  112. "error",
  113. "NUMBER",
  114. "R",
  115. "U",
  116. "C",
  117. "F",
  118. "PLUS",
  119. "MINUS",
  120. "ASTERISK",
  121. "SLASH",
  122. "PARENL",
  123. "PARENR",
  124. "$start",
  125. "add",
  126. "mul",
  127. "unary",
  128. "round_type",
  129. "term" ]
  130. 1 then: 1 else: 0 Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
  131. 1 Racc_debug_parser = false
  132. ##### State transition tables end #####
  133. # reduce 0 omitted
  134. 1 def _reduce_1(val, _values, result)
  135. 376 result = Arithmetic::Node::BinaryOp.new(val[0], :+, val[2])
  136. 376 result
  137. end
  138. 1 def _reduce_2(val, _values, result)
  139. 409 result = Arithmetic::Node::BinaryOp.new(val[0], :-, val[2])
  140. 409 result
  141. end
  142. # reduce 3 omitted
  143. 1 def _reduce_4(val, _values, result)
  144. 99 result = Arithmetic::Node::BinaryOp.new(val[0], :*, val[2])
  145. 99 result
  146. end
  147. 1 def _reduce_5(val, _values, result)
  148. 80 divied_class = val[3]
  149. 80 result = divied_class.new(val[0], val[2])
  150. 80 result
  151. end
  152. # reduce 6 omitted
  153. 1 def _reduce_7(val, _values, result)
  154. 72 result = Arithmetic::Node::DivideWithGameSystemDefault
  155. 72 result
  156. end
  157. 1 def _reduce_8(val, _values, result)
  158. 1 result = Arithmetic::Node::DivideWithCeil
  159. 1 result
  160. end
  161. 1 def _reduce_9(val, _values, result)
  162. 5 result = Arithmetic::Node::DivideWithCeil
  163. 5 result
  164. end
  165. 1 def _reduce_10(val, _values, result)
  166. 1 result = Arithmetic::Node::DivideWithRound
  167. 1 result
  168. end
  169. 1 def _reduce_11(val, _values, result)
  170. 1 result = Arithmetic::Node::DivideWithFloor
  171. 1 result
  172. end
  173. 1 def _reduce_12(val, _values, result)
  174. 722 result = val[1]
  175. 722 result
  176. end
  177. 1 def _reduce_13(val, _values, result)
  178. 248 result = Arithmetic::Node::Negative.new(val[1])
  179. 248 result
  180. end
  181. # reduce 14 omitted
  182. 1 def _reduce_15(val, _values, result)
  183. 565 result = val[1]
  184. 565 result
  185. end
  186. 1 def _reduce_16(val, _values, result)
  187. 4026 result = Arithmetic::Node::Number.new(val[0])
  188. 4026 result
  189. end
  190. 1 def _reduce_none(val, _values, result)
  191. val[0]
  192. end
  193. end # class Parser
  194. end # module Arithmetic
  195. end # module BCDice

lib/bcdice/arithmetic_evaluator.rb

100.0% lines covered

100.0% branches covered

6 relevant lines. 6 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module ArithmeticEvaluator
  4. 1 class << self
  5. # 四則演算を評価する
  6. # @deprecated +Arithmetic.#eval+ を利用してください。
  7. # @param expr [String, nil] 評価する式
  8. # @param round_type [Symbol] 端数処理の種類
  9. # @return [Integer] 評価結果を返す。不正な式の場合には0を返す。
  10. 1 def eval(expr, round_type: RoundType::FLOOR)
  11. 2379 else: 2075 then: 304 return 0 unless expr
  12. 2075 Arithmetic.eval(expr, round_type) || 0
  13. end
  14. end
  15. end
  16. end

lib/bcdice/base.rb

95.81% lines covered

83.61% branches covered

191 relevant lines. 183 lines covered and 8 lines missed.
61 total branches, 51 branches covered and 10 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "i18n"
  3. 1 require "i18n/backend/fallbacks"
  4. 1 require "bcdice/randomizer"
  5. 1 require "bcdice/dice_table"
  6. 1 require "bcdice/enum"
  7. 1 require "bcdice/translate"
  8. 1 require "bcdice/result"
  9. 1 require "bcdice/command/parser"
  10. 1 require "bcdice/deprecated/checker"
  11. 1 module BCDice
  12. 1 class Base
  13. 1 class << self
  14. # 接頭辞(反応するコマンド)の配列を返す
  15. # @return [Array<String>]
  16. 1 attr_reader :prefixes
  17. # 応答するコマンドのprefixを登録する
  18. # @param prefixes [Array<String>]
  19. 1 def register_prefix(*prefixes)
  20. 290 @prefixes ||= []
  21. 290 @prefixes.concat(prefixes.flatten)
  22. end
  23. 1 def register_prefix_from_super_class
  24. 31 register_prefix(superclass.prefixes)
  25. end
  26. # ゲームシステム固有のコマンドにマッチする正規表現を返す
  27. # 正規表現を一度生成したら、以後コマンドの登録はできないようにする
  28. #
  29. # @return [Regexp]
  30. 1 def prefixes_pattern
  31. 17961 @prefixes_pattern ||= nil
  32. 17961 then: 17665 else: 296 return @prefixes_pattern if @prefixes_pattern
  33. 296 @prefixes ||= []
  34. 296 @prefixes.freeze
  35. @prefixes_pattern =
  36. 296 then: 30 if @prefixes.empty?
  37. 30 /(?!)/ # 何にもマッチしない正規表現
  38. else: 266 else
  39. 266 /^(S)?(#{@prefixes.join('|')})/i
  40. end.freeze
  41. end
  42. # 応答するコマンド全てにマッチする正規表現を返す
  43. # 正規表現を一度生成したら、以後コマンドの登録はできないようにする
  44. #
  45. # @return [Regexp]
  46. 1 def command_pattern
  47. 17519 @command_pattern ||= nil
  48. 17519 then: 17227 else: 292 return @command_pattern if @command_pattern
  49. 292 @prefixes ||= []
  50. 292 @prefixes.freeze
  51. 3212 pattarns = CommonCommand::COMMANDS.map { |c| c::PREFIX_PATTERN.source } + @prefixes
  52. 292 @command_pattern = /^S?(#{pattarns.join('|')})/i.freeze
  53. end
  54. # @param command [String]
  55. # @return [Result]
  56. 1 def eval(command)
  57. 13 new(command).eval
  58. end
  59. end
  60. 1 include Translate
  61. 1 include Deprecated::Checker
  62. 1 def initialize(command)
  63. 17970 @raw_input = command
  64. 17970 @sort_add_dice = false # 加算ダイスでダイス目をソートするかどうか
  65. 17970 @sort_barabara_dice = false # バラバラダイスでダイス目をソートするかどうか
  66. 17970 @d66_sort_type = D66SortType::NO_SORT # 入れ替えの種類 詳しくはBCDice::D66SortTypeを参照すること
  67. 17970 @enabled_d9 = false # D9ダイスを有効にするか(ガンドッグ)で使用
  68. 17970 @round_type = RoundType::FLOOR # 割り算をした時の端数の扱い (FLOOR: 切り捨て, CEIL: 切り上げ, ROUND: 四捨五入)
  69. 17970 @sides_implicit_d = 6 # 1D のようにダイスの面数が指定されていない場合に何面ダイスにするか
  70. 17970 @upper_dice_reroll_threshold = nil # UpperDiceで振り足しをする出目の閾値 nilの場合デフォルト設定なし
  71. 17970 @reroll_dice_reroll_threshold = nil # RerollDiceで振り足しをする出目の閾値 nilの場合デフォルト設定なし
  72. 17970 @default_cmp_op = nil # 目標値が空欄の場合の比較演算子をシンボルで指定する (:>, :>= :<, :<=, :==, :!=)
  73. 17970 @default_target_number = nil # 目標値が空欄の場合の目標値 こちらだけnilにするのは想定していないので注意
  74. 17970 @enabled_upcase_input = true # 入力を String#upcase するかどうか
  75. 17970 @locale = :ja_jp # i18n用の言語設定
  76. 17970 @randomizer = BCDice::Randomizer.new
  77. 17970 @debug = false
  78. end
  79. 1 attr_accessor :randomizer
  80. # D66のダイス入れ替えの種類
  81. #
  82. # @return [Symbol]
  83. 1 attr_reader :d66_sort_type
  84. # 端数処理の種類
  85. #
  86. # @return [Symbol]
  87. 1 attr_reader :round_type
  88. # ダイスの面数が指定されていない場合に何面ダイスにするか
  89. #
  90. # @return [Integer]
  91. 1 attr_reader :sides_implicit_d
  92. # UpperDiceで振り足しをする出目の閾値
  93. #
  94. # @return [Integer, nil]
  95. 1 attr_reader :upper_dice_reroll_threshold
  96. # RerollDiceで振り足しをする出目の閾値
  97. #
  98. # @return [Integer, nil]
  99. 1 attr_reader :reroll_dice_reroll_threshold
  100. # デフォルトの比較演算子
  101. #
  102. # @return [Symbol, nil]
  103. 1 attr_reader :default_cmp_op
  104. # デフォルトの目標値
  105. #
  106. # @return [Integer, nil]
  107. 1 attr_reader :default_target_number
  108. # 加算ダイスでダイス目をソートするかどうか
  109. #
  110. # @return [Boolean]
  111. 1 def sort_add_dice?
  112. 1261 @sort_add_dice
  113. end
  114. # バラバラダイスでダイス目をソートするかどうか
  115. #
  116. # @return [Boolean]
  117. 1 def sort_barabara_dice?
  118. 268 @sort_barabara_dice
  119. end
  120. # D9ダイスが有効か
  121. #
  122. # @return [Boolean]
  123. 1 def enabled_d9?
  124. 4 @enabled_d9
  125. end
  126. # デバッグを有用にする
  127. 1 def enable_debug
  128. @debug = true
  129. end
  130. # コマンドを評価する
  131. # @return [Result, nil] コマンド実行結果。コマンドが実行できなかった場合はnilを返す
  132. 1 def eval
  133. 17961 command = BCDice::Preprocessor.process(@raw_input, self)
  134. 17961 result = dice_command(command) || eval_common_command(@raw_input)
  135. 17959 else: 17746 then: 213 return nil unless result
  136. 17746 result.rands = @randomizer.rand_results
  137. 17746 result.detailed_rands = @randomizer.detailed_rand_results
  138. 17746 return result
  139. end
  140. # ゲームシステムごとの入力コマンドの前処理
  141. # @deprecated これを使わずに +eval_common_command+ 内でパースすることを推奨する
  142. # @param string [String]
  143. # @return [String]
  144. 1 def change_text(string)
  145. 19588 string
  146. end
  147. # @param total [Integer] コマンド合計値
  148. # @param rand_results [Array<CommonCommand::AddDice::Randomizer::RandResult>] ダイスの一覧
  149. # @param cmp_op [Symbol] 比較演算子
  150. # @param target [Integer, String] 目標値の整数か'?'
  151. # @return [Result, nil]
  152. 1 def check_result(total, rand_results, cmp_op, target)
  153. 811 ret = check_result_legacy(total, rand_results, cmp_op, target)
  154. 811 then: 13 else: 798 return ret if ret
  155. 798 sides_list = rand_results.map(&:sides)
  156. 798 value_list = rand_results.map(&:value)
  157. 798 dice_total = value_list.sum()
  158. ret =
  159. 798 else: 165 case sides_list
  160. when: 257 when [100]
  161. 257 result_1d100(total, dice_total, cmp_op, target)
  162. when: 62 when [20]
  163. 62 result_1d20(total, dice_total, cmp_op, target)
  164. when: 314 when [6, 6]
  165. 314 result_2d6(total, dice_total, value_list, cmp_op, target)
  166. end
  167. 798 then: 18 else: 780 return nil if ret == Result.nothing
  168. 780 then: 430 else: 350 return ret if ret
  169. ret =
  170. 350 else: 60 case sides_list.uniq
  171. when: 52 when [10]
  172. 52 result_nd10(total, dice_total, value_list, cmp_op, target)
  173. when: 238 when [6]
  174. 238 result_nd6(total, dice_total, value_list, cmp_op, target)
  175. end
  176. 350 then: 4 else: 346 return nil if ret == Result.nothing
  177. 346 then: 149 else: 197 return ret if ret
  178. 197 return result_ndx(total, cmp_op, target)
  179. end
  180. # シャドウラン用グリッチ判定
  181. # @param count_one [Integer] 出目1の数
  182. # @param dice_total_count [Integer] ダイスロールしたダイスの数
  183. # @param count_success [Integer] 成功数
  184. # @return [String, nil]
  185. 1 def grich_text(count_one, dice_total_count, count_success); end
  186. 1 private
  187. 1 def eval_common_command(command)
  188. 1819 command = change_text(command)
  189. 1819 CommonCommand::COMMANDS.each do |klass|
  190. 5706 result = klass.eval(command, self, @randomizer)
  191. 5704 then: 1604 else: 4100 return result if result
  192. end
  193. 213 return nil
  194. end
  195. 1 def dice_command(command)
  196. 17961 then: 17860 else: 101 command = command.upcase if @enabled_upcase_input
  197. 17961 m = self.class.prefixes_pattern.match(command)
  198. 17961 else: 16329 then: 1632 unless m
  199. 1632 return nil
  200. end
  201. 16329 secret = !m[1].nil?
  202. 16329 then: 473 else: 15856 command = command[1..-1] if secret # 先頭の 'S' をとる
  203. 16329 output = eval_game_system_specific_command(command)
  204. 16329 then: 4880 if output.is_a?(Result)
  205. 4880 output.secret = output.secret? || secret
  206. 4880 else: 11449 return output
  207. 11449 then: 186 elsif output.nil? || output.empty? || output == "1"
  208. 186 return nil
  209. else: 11263 else
  210. 11263 return Result.new.tap do |r|
  211. 11263 r.text = output.to_s
  212. 11263 r.secret = secret
  213. end
  214. end
  215. end
  216. # @param command [String]
  217. # @return [String, nil]
  218. 1 def eval_game_system_specific_command(command); end
  219. # 成功か失敗か返す
  220. #
  221. # @param total [Integer]
  222. # @param cmp_op [Symbol]
  223. # @param target [Number]
  224. # @return [Result]
  225. 1 def result_ndx(total, cmp_op, target)
  226. 197 then: 44 if target.is_a?(String)
  227. 44 else: 153 nil
  228. 153 then: 93 elsif total.send(cmp_op, target)
  229. 93 Result.success(translate("success"))
  230. else: 60 else
  231. 60 Result.failure(translate("failure"))
  232. end
  233. end
  234. 1 def result_1d100(total, dice_total, cmp_op, target); end
  235. 1 def result_1d20(total, dice_total, cmp_op, target); end
  236. 1 def result_nd10(total, dice_total, value_list, cmp_op, target); end
  237. 1 def result_2d6(total, dice_total, value_list, cmp_op, target); end
  238. 1 def result_nd6(total, dice_total, value_list, cmp_op, target); end
  239. 1 def get_table_by_2d6(table)
  240. 241 get_table_by_nD6(table, 2)
  241. end
  242. 1 def get_table_by_1d6(table)
  243. 154 get_table_by_nD6(table, 1)
  244. end
  245. 1 def get_table_by_nD6(table, count)
  246. 400 get_table_by_nDx(table, count, 6)
  247. end
  248. 1 def get_table_by_nDx(table, count, diceType)
  249. 410 num = @randomizer.roll_sum(count, diceType)
  250. 410 text = get_table_value(table[num - count])
  251. 410 then: 0 else: 410 return "1", 0 if text.nil?
  252. 410 return text, num
  253. end
  254. 1 def get_table_by_1d3(table)
  255. 10 debug("get_table_by_1d3")
  256. 10 count = 1
  257. 10 num = @randomizer.roll_sum(count, 6)
  258. 10 debug("num", num)
  259. 10 index = ((num - 1) / 2)
  260. 10 debug("index", index)
  261. 10 text = table[index]
  262. 10 then: 0 else: 10 return "1", 0 if text.nil?
  263. 10 return text, num
  264. end
  265. # D66 ロール用(スワップ、たとえば出目が【6,4】なら「64」ではなく「46」とする
  266. 1 def get_table_by_d66_swap(table)
  267. 85 number = @randomizer.roll_d66(D66SortType::ASC)
  268. 85 return get_table_by_number(number, table), number
  269. end
  270. # D66 ロール用
  271. 1 def get_table_by_d66(table)
  272. 158 dice1 = @randomizer.roll_once(6)
  273. 158 dice2 = @randomizer.roll_once(6)
  274. 158 num = (dice1 - 1) * 6 + (dice2 - 1)
  275. 158 text = table[num]
  276. 158 indexText = "#{dice1}#{dice2}"
  277. 158 then: 0 else: 158 return "1", indexText if text.nil?
  278. 158 return text, indexText
  279. end
  280. # ** 汎用表サブルーチン
  281. 1 def get_table_by_number(index, table, default = "1")
  282. 1938 table.each do |item|
  283. 13653 number = item[0]
  284. 13653 then: 1938 else: 11715 if number >= index
  285. 1938 return get_table_value(item[1])
  286. end
  287. end
  288. return get_table_value(default)
  289. end
  290. 1 def get_table_value(data)
  291. 2348 then: 446 else: 1902 if data.is_a?(Proc)
  292. 446 return data.call()
  293. end
  294. 1902 return data
  295. end
  296. 1 def roll_tables(command, tables)
  297. 4490 table = tables[command]
  298. 4490 else: 3548 then: 942 unless table
  299. 942 return nil
  300. end
  301. 3548 return table.roll(@randomizer).to_s
  302. end
  303. # デバッグ出力を行う
  304. # @param [Object] target 対象項目
  305. # @param [Object] values 値
  306. 1 def debug(target, *values)
  307. 23439 else: 0 then: 23439 return unless @debug
  308. then: 0 else: 0 targetStr = target.is_a?(String) ? target : target.inspect
  309. then: 0 if values.empty?
  310. warn targetStr
  311. else: 0 else
  312. valueStrs = values.map do |value|
  313. then: 0 else: 0 value.is_a?(String) ? %("#{value}") : value.inspect
  314. end
  315. warn "#{targetStr}: #{valueStrs.join(', ')}"
  316. end
  317. end
  318. end
  319. end
  320. 1 I18n::Backend::Simple.include(I18n::Backend::Fallbacks)
  321. 1 I18n.load_path << Dir[File.join(__dir__, "../../i18n/**/*.yml")]
  322. 1 I18n.default_locale = :ja_jp
  323. 1 I18n.fallbacks.defaults = [:ja_jp]

lib/bcdice/command/lexer.rb

96.3% lines covered

81.25% branches covered

27 relevant lines. 26 lines covered and 1 lines missed.
16 total branches, 13 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "strscan"
  3. 1 require "bcdice/normalize"
  4. 1 module BCDice
  5. 1 module Command
  6. 1 class Lexer
  7. 1 SYMBOLS = {
  8. "+" => :PLUS,
  9. "-" => :MINUS,
  10. "*" => :ASTERISK,
  11. "/" => :SLASH,
  12. "(" => :PARENL,
  13. ")" => :PARENR,
  14. "?" => :QUESTION,
  15. "@" => :AT,
  16. "#" => :SHARP,
  17. "$" => :DOLLAR,
  18. }.freeze
  19. 1 def initialize(source, notations)
  20. # sourceが空文字だとString#splitが空になる
  21. 3662 then: 3662 else: 0 then: 3662 else: 0 source = source&.split(" ", 2)&.first || ""
  22. 3662 @scanner = StringScanner.new(source)
  23. 3662 @notations = notations.map do |n|
  24. 3810 then: 1797 else: 2013 n.is_a?(String) ? Regexp.new(n) : n
  25. end
  26. end
  27. 1 def next_token
  28. 11161 then: 1748 else: 9413 return [false, "$"] if @scanner.eos?
  29. 9413 @notations.each do |n|
  30. 9921 token = @scanner.scan(n)
  31. 9921 then: 1836 else: 8085 return [:NOTATION, token] if token
  32. end
  33. 7577 then: 3076 if (number = @scanner.scan(/\d+/))
  34. 3076 else: 4501 [:NUMBER, number.to_i]
  35. 4501 then: 836 elsif (cmp_op = @scanner.scan(/[<>!=]+/))
  36. 836 cmp_op = Normalize.comparison_operator(cmp_op)
  37. 836 then: 836 else: 0 type = cmp_op ? :CMP_OP : :ILLEGAL
  38. 836 [type, cmp_op]
  39. else: 3665 else
  40. 3665 char = @scanner.getch.upcase
  41. 3665 type = SYMBOLS[char] || char.to_sym
  42. 3665 [type, char]
  43. end
  44. end
  45. 1 def source
  46. @scanner.string
  47. end
  48. end
  49. end
  50. end

lib/bcdice/command/parsed.rb

97.06% lines covered

83.33% branches covered

34 relevant lines. 33 lines covered and 1 lines missed.
12 total branches, 10 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module Command
  4. 1 class Parsed
  5. # @return [String]
  6. 1 attr_accessor :command
  7. # @return [Integer, nil]
  8. 1 attr_accessor :prefix_number
  9. # @return [Integer, nil]
  10. 1 attr_accessor :suffix_number
  11. # @return [Integer, nil]
  12. 1 attr_accessor :critical
  13. # @return [Integer, nil]
  14. 1 attr_accessor :fumble
  15. # @return [Integer, nil]
  16. 1 attr_accessor :dollar
  17. # @return [Integer]
  18. 1 attr_accessor :modify_number
  19. # @return [Symbol, nil]
  20. 1 attr_accessor :cmp_op
  21. # @return [Integer, nil]
  22. 1 attr_accessor :target_number
  23. # @param value [Boolean]
  24. # @return [Boolean]
  25. 1 attr_writer :question_target
  26. 1 def initialize
  27. 1764 @prefix_number = nil
  28. 1764 @suffix_number = nil
  29. 1764 @critical = nil
  30. 1764 @fumble = nil
  31. 1764 @dollar = nil
  32. 1764 @cmp_op = nil
  33. 1764 @target_number = nil
  34. 1764 @question_target = false
  35. end
  36. # @return [Boolean]
  37. 1 def question_target?
  38. 166 @question_target
  39. end
  40. # @param suffix_position [Symbol] クリティカルなどの表示位置
  41. # @return [String]
  42. 1 def to_s(suffix_position = :after_command)
  43. 731 then: 130 else: 601 c = @critical ? "@#{@critical}" : nil
  44. 731 then: 112 else: 619 f = @fumble ? "##{@fumble}" : nil
  45. 731 then: 30 else: 701 d = @dollar ? "$#{@dollar}" : nil
  46. 731 m = Format.modifier(@modify_number)
  47. 731 then: 34 else: 697 target = @question_target ? "?" : @target_number
  48. 731 else: 0 case suffix_position
  49. when: 568 when :after_command
  50. 568 [@prefix_number, @command, @suffix_number, c, f, d, m, @cmp_op, target].join()
  51. when: 163 when :after_modify_number
  52. 163 [@prefix_number, @command, @suffix_number, m, c, f, d, @cmp_op, target].join()
  53. when: 0 when :after_target_number
  54. [@prefix_number, @command, @suffix_number, m, @cmp_op, target, c, f, d].join()
  55. end
  56. end
  57. end
  58. end
  59. end

lib/bcdice/command/parser.rb

94.93% lines covered

89.58% branches covered

217 relevant lines. 206 lines covered and 11 lines missed.
48 total branches, 43 branches covered and 5 branches missed.
    
  1. #
  2. # DO NOT MODIFY!!!!
  3. # This file is automatically generated by Racc 1.7.3
  4. # from Racc grammar file "parser.y".
  5. #
  6. 1 require 'racc/parser.rb'
  7. 1 require "bcdice/arithmetic/node"
  8. 1 require "bcdice/command/lexer"
  9. 1 require "bcdice/command/parsed"
  10. # よくある形式のコマンドのパースを補助するクラス
  11. #
  12. # @example Literal by String
  13. # parser = Command::Parser.new("MC", round_type: BCDice::RoundType::FLOOR)
  14. # .enable_critical
  15. # parsed = parser.parse("MC+2*3@30<=10/2-3") #=> <Command::Parsed>
  16. #
  17. # parsed.command #=> "MC"
  18. # parsed.modify_number #=> 6
  19. # parsed.critical #=> 30
  20. # parsed.cmp_op #=> #>=
  21. # parsed.target_number #=> 2
  22. #
  23. # @example Literal by Regexp
  24. # parser = Command::Parser.new(/RE\d+/)
  25. # parsed = parser.parse("RE44+20") #=> <Command::Parsed>
  26. #
  27. # parsed.command #=> "RE44"
  28. # parsed.modify_number #=> 20
  29. 1 class BCDice::Command::Parser < Racc::Parser; end
  30. 1 module BCDice
  31. 1 module Command
  32. 1 class Parser < Racc::Parser
  33. # @param notations [Array<String, Regexp>] 反応するコマンドの表記
  34. # @param round_type [Symbol] 除算での端数の扱い
  35. 1 def initialize(*notations, round_type:)
  36. 3627 super()
  37. 3627 @notations = notations
  38. 3627 @round_type = round_type
  39. 3627 @prefix_number = false
  40. 3627 @suffix_number = false
  41. 3627 @need_prefix_number = false
  42. 3627 @need_suffix_number = false
  43. 3627 @modifier = true
  44. 3627 @critical = false
  45. 3627 @fumble = false
  46. 3627 @dollar = false
  47. 3627 @allowed_cmp_op = [nil, :>=, :>, :<=, :<, :==, :!=]
  48. 3627 @question_target = false
  49. end
  50. # 修正値は受け付けないようにする
  51. # @return [BCDice::Command::Parser]
  52. 1 def disable_modifier
  53. 124 @modifier = false
  54. 124 self
  55. end
  56. # リテラルの前に数値を許可する
  57. # @return [BCDice::Command::Parser]
  58. 1 def enable_prefix_number
  59. 301 @prefix_number = true
  60. 301 self
  61. end
  62. # リテラルの後ろに数値を許可する
  63. # @return [BCDice::Command::Parser]
  64. 1 def enable_suffix_number
  65. 264 @suffix_number = true
  66. 264 self
  67. end
  68. # リテラルの前に数値が必要であると設定する
  69. # @return [BCDice::Command::Parser]
  70. 1 def has_prefix_number
  71. 383 @prefix_number = true
  72. 383 @need_prefix_number = true
  73. 383 self
  74. end
  75. # リテラルの後ろに数値が必要であると設定する
  76. # @return [BCDice::Command::Parser]
  77. 1 def has_suffix_number
  78. 444 @suffix_number = true
  79. 444 @need_suffix_number = true
  80. 444 self
  81. end
  82. # +@+によるクリティカル値の指定を許可する
  83. # @return [BCDice::Command::Parser]
  84. 1 def enable_critical
  85. 1412 @critical = true
  86. 1412 self
  87. end
  88. # +#+によるファンブル値の指定を許可する
  89. # @return [BCDice::Command::Parser]
  90. 1 def enable_fumble
  91. 898 @fumble = true
  92. 898 self
  93. end
  94. # +$+による値の指定を許可する
  95. # @return [BCDice::Command::Parser]
  96. 1 def enable_dollar
  97. 229 @dollar = true
  98. 229 self
  99. end
  100. # 使用できる比較演算子を制限する。
  101. # 目標値未入力を許可する場合には+nil+を指定する。
  102. # @param ops [Array<nil, Symbol>] 許可する比較演算子の一覧
  103. # @return [BCDice::Command::Parser]
  104. 1 def restrict_cmp_op_to(*ops)
  105. 3044 @allowed_cmp_op = ops
  106. 3044 self
  107. end
  108. # 目標値"?"の指定を許可する
  109. # @return [BCDice::Command::Parser]
  110. 1 def enable_question_target
  111. 271 @question_target = true
  112. 271 self
  113. end
  114. # @param source [String]
  115. # @return [BCDice::Command::Parsed, nil]
  116. 1 def parse(source)
  117. 3662 @lexer = Lexer.new(source, @notations)
  118. 3662 do_parse()
  119. rescue ParseError, ZeroDivisionError
  120. 1922 nil
  121. end
  122. 1 private
  123. 1 def parsed(notation, option, modifier, target)
  124. 1764 Parsed.new.tap do |p|
  125. 1764 p.command = notation[:command]
  126. 1764 then: 266 else: 1498 p.prefix_number = notation[:prefix]&.eval(@round_type)
  127. 1764 then: 155 else: 1609 p.suffix_number = notation[:suffix]&.eval(@round_type)
  128. 1764 then: 439 else: 1325 p.critical = option[:critical]&.eval(@round_type)
  129. 1764 then: 207 else: 1557 p.fumble = option[:fumble]&.eval(@round_type)
  130. 1764 then: 70 else: 1694 p.dollar = option[:dollar]&.eval(@round_type)
  131. 1764 p.modify_number = modifier.eval(@round_type)
  132. 1764 p.cmp_op = target[:cmp_op]
  133. 1764 then: 35 if target[:target] == "?"
  134. 35 p.question_target = true
  135. 35 p.target_number = 0
  136. else: 1729 else
  137. 1729 p.question_target = false
  138. 1729 then: 796 else: 933 p.target_number = target[:target]&.eval(@round_type)
  139. end
  140. end
  141. end
  142. 1 def next_token
  143. 11161 @lexer.next_token
  144. end
  145. ##### State transition tables begin ###
  146. 1 racc_action_table = [
  147. 6, 6, 6, 6, 7, 28, 29, 17, 18, 5,
  148. 5, 5, 5, 6, 26, 12, 4, 45, 17, 18,
  149. 10, 11, 5, 10, 11, 6, 23, 24, 25, 26,
  150. 17, 18, 6, 20, 5, 33, 34, 17, 18, 6,
  151. 35, 5, 28, 29, 17, 18, 6, nil, 5, 36,
  152. 37, 17, 18, 6, nil, 5, 36, 37, 17, 18,
  153. 6, nil, 5, 36, 37, 17, 18, 6, nil, 5,
  154. 33, 34, 17, 18, 6, nil, 5, 36, 37, 17,
  155. 18, 6, nil, 5, 36, 37, 17, 18, 6, nil,
  156. 5, 36, 37, 17, 18, 6, nil, 5, 36, 37,
  157. 17, 18, 6, nil, 5, nil, nil, 17, 18, 6,
  158. nil, 5, nil, nil, 17, 18, nil, nil, 5, 23,
  159. 24, 25, 26, 56, 54, 55, 57 ]
  160. 1 racc_action_check = [
  161. 0, 4, 26, 12, 1, 21, 21, 26, 26, 0,
  162. 4, 26, 12, 5, 21, 3, 0, 26, 5, 5,
  163. 8, 8, 5, 2, 2, 10, 8, 8, 8, 8,
  164. 10, 10, 11, 7, 10, 14, 14, 11, 11, 17,
  165. 14, 11, 9, 9, 17, 17, 18, nil, 17, 15,
  166. 15, 18, 18, 23, nil, 18, 30, 30, 23, 23,
  167. 24, nil, 23, 31, 31, 24, 24, 25, nil, 24,
  168. 44, 44, 25, 25, 28, nil, 25, 47, 47, 28,
  169. 28, 29, nil, 28, 48, 48, 29, 29, 33, nil,
  170. 29, 49, 49, 33, 33, 34, nil, 33, 50, 50,
  171. 34, 34, 36, nil, 34, nil, nil, 36, 36, 37,
  172. nil, 36, nil, nil, 37, 37, nil, nil, 37, 27,
  173. 27, 27, 27, 52, 52, 52, 52 ]
  174. 1 racc_action_pointer = [
  175. -2, 4, 16, -3, -1, 11, nil, 33, 13, 35,
  176. 23, 30, 1, nil, 28, 40, nil, 37, 44, nil,
  177. nil, -2, nil, 51, 58, 65, 0, 106, 72, 79,
  178. 47, 54, nil, 86, 93, nil, 100, 107, nil, nil,
  179. nil, nil, nil, nil, 63, nil, nil, 68, 75, 82,
  180. 89, nil, 120, nil, nil, nil, nil, nil ]
  181. 1 racc_action_default = [
  182. -35, -35, -8, -35, -7, -35, -34, -35, -16, -8,
  183. -35, -35, -5, -6, -35, -21, -24, -35, -35, -32,
  184. 58, -16, -3, -35, -35, -35, -35, -16, -35, -35,
  185. -12, -13, -4, -35, -35, -33, -35, -35, -30, -31,
  186. -1, -9, -10, -11, -17, -18, -2, -14, -15, -19,
  187. -20, -22, -25, -23, -26, -27, -28, -29 ]
  188. 1 racc_goto_table = [
  189. 30, 31, 38, 39, 14, 8, 1, 22, 41, 42,
  190. 43, 9, 27, 2, 53, nil, nil, 21, 47, 48,
  191. 40, 51, 52, 49, 50, 44, 46, 3, nil, nil,
  192. nil, 13, nil, nil, nil, nil, nil, nil, nil, 32 ]
  193. 1 racc_goto_check = [
  194. 8, 8, 7, 7, 9, 3, 1, 5, 7, 7,
  195. 7, 4, 3, 2, 10, nil, nil, 4, 8, 8,
  196. 5, 7, 7, 8, 8, 9, 5, 6, nil, nil,
  197. nil, 6, nil, nil, nil, nil, nil, nil, nil, 6 ]
  198. 1 racc_goto_pointer = [
  199. nil, 6, 13, 3, 9, -1, 27, -15, -10, -1,
  200. -38 ]
  201. 1 racc_goto_default = [
  202. nil, nil, nil, nil, nil, nil, 19, 16, 15, nil,
  203. nil ]
  204. 1 racc_reduce_table = [
  205. 0, 0, :racc_error,
  206. 4, 20, :_reduce_1,
  207. 4, 20, :_reduce_2,
  208. 3, 20, :_reduce_3,
  209. 3, 21, :_reduce_4,
  210. 2, 21, :_reduce_5,
  211. 2, 21, :_reduce_6,
  212. 1, 21, :_reduce_7,
  213. 0, 22, :_reduce_8,
  214. 3, 22, :_reduce_9,
  215. 3, 22, :_reduce_10,
  216. 3, 22, :_reduce_11,
  217. 2, 23, :_reduce_12,
  218. 2, 23, :_reduce_13,
  219. 3, 23, :_reduce_14,
  220. 3, 23, :_reduce_15,
  221. 0, 24, :_reduce_16,
  222. 2, 24, :_reduce_17,
  223. 2, 24, :_reduce_18,
  224. 3, 28, :_reduce_19,
  225. 3, 28, :_reduce_20,
  226. 1, 28, :_reduce_none,
  227. 3, 27, :_reduce_22,
  228. 4, 27, :_reduce_23,
  229. 1, 27, :_reduce_none,
  230. 0, 29, :_reduce_25,
  231. 1, 29, :_reduce_26,
  232. 1, 29, :_reduce_27,
  233. 1, 29, :_reduce_28,
  234. 1, 29, :_reduce_29,
  235. 2, 26, :_reduce_30,
  236. 2, 26, :_reduce_31,
  237. 1, 26, :_reduce_none,
  238. 3, 25, :_reduce_33,
  239. 1, 25, :_reduce_34 ]
  240. 1 racc_reduce_n = 35
  241. 1 racc_shift_n = 58
  242. 1 racc_token_table = {
  243. false => 0,
  244. :error => 1,
  245. :NUMBER => 2,
  246. :R => 3,
  247. :U => 4,
  248. :C => 5,
  249. :F => 6,
  250. :PLUS => 7,
  251. :MINUS => 8,
  252. :ASTERISK => 9,
  253. :SLASH => 10,
  254. :PARENL => 11,
  255. :PARENR => 12,
  256. :AT => 13,
  257. :SHARP => 14,
  258. :DOLLAR => 15,
  259. :CMP_OP => 16,
  260. :QUESTION => 17,
  261. :NOTATION => 18 }
  262. 1 racc_nt_base = 19
  263. 1 racc_use_result_var = true
  264. Racc_arg = [
  265. 1 racc_action_table,
  266. racc_action_check,
  267. racc_action_default,
  268. racc_action_pointer,
  269. racc_goto_table,
  270. racc_goto_check,
  271. racc_goto_default,
  272. racc_goto_pointer,
  273. racc_nt_base,
  274. racc_reduce_table,
  275. racc_token_table,
  276. racc_shift_n,
  277. racc_reduce_n,
  278. racc_use_result_var ]
  279. 1 then: 1 else: 0 Ractor.make_shareable(Racc_arg) if defined?(Ractor)
  280. 1 Racc_token_to_s_table = [
  281. "$end",
  282. "error",
  283. "NUMBER",
  284. "R",
  285. "U",
  286. "C",
  287. "F",
  288. "PLUS",
  289. "MINUS",
  290. "ASTERISK",
  291. "SLASH",
  292. "PARENL",
  293. "PARENR",
  294. "AT",
  295. "SHARP",
  296. "DOLLAR",
  297. "CMP_OP",
  298. "QUESTION",
  299. "NOTATION",
  300. "$start",
  301. "expr",
  302. "notation",
  303. "option",
  304. "modifier",
  305. "target",
  306. "term",
  307. "unary",
  308. "mul",
  309. "add",
  310. "round_type" ]
  311. 1 then: 1 else: 0 Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
  312. 1 Racc_debug_parser = false
  313. ##### State transition tables end #####
  314. # reduce 0 omitted
  315. 1 def _reduce_1(val, _values, result)
  316. 114 else: 114 then: 0 raise ParseError unless @modifier
  317. 114 notation, option, modifier, target = val
  318. 114 result = parsed(notation, option, modifier, target)
  319. 114 result
  320. end
  321. 1 def _reduce_2(val, _values, result)
  322. 710 else: 709 then: 1 raise ParseError unless @modifier
  323. 709 notation, modifier, option, target = val
  324. 709 result = parsed(notation, option, modifier, target)
  325. 709 result
  326. end
  327. 1 def _reduce_3(val, _values, result)
  328. 941 notation, option, target = val
  329. 941 result = parsed(notation, option, Arithmetic::Node::Number.new(0), target)
  330. 941 result
  331. end
  332. 1 def _reduce_4(val, _values, result)
  333. 52 else: 52 then: 0 raise ParseError unless @prefix_number && @suffix_number
  334. 52 result = { command: val[1], prefix: val[0], suffix: val[2] }
  335. 52 result
  336. end
  337. 1 def _reduce_5(val, _values, result)
  338. 216 else: 215 then: 1 raise ParseError unless @prefix_number
  339. 215 then: 1 else: 214 raise ParseError if @need_suffix_number
  340. 214 result = { command: val[1], prefix: val[0] }
  341. 214 result
  342. end
  343. 1 def _reduce_6(val, _values, result)
  344. 153 else: 104 then: 49 raise ParseError unless @suffix_number
  345. 104 then: 1 else: 103 raise ParseError if @need_prefix_number
  346. 103 result = { command: val[0], suffix: val[1] }
  347. 103 result
  348. end
  349. 1 def _reduce_7(val, _values, result)
  350. 1415 then: 5 else: 1410 raise ParseError if @need_prefix_number || @need_suffix_number
  351. 1410 result = { command: val[0] }
  352. 1410 result
  353. end
  354. 1 def _reduce_8(val, _values, result)
  355. 1779 result = {}
  356. 1779 result
  357. end
  358. 1 def _reduce_9(val, _values, result)
  359. 444 option, _, term = val
  360. 444 else: 440 then: 4 raise ParseError unless @critical && option[:critical].nil?
  361. 440 option[:critical] = term
  362. 440 result = option
  363. 440 result
  364. end
  365. 1 def _reduce_10(val, _values, result)
  366. 209 option, _, term = val
  367. 209 else: 208 then: 1 raise ParseError unless @fumble && option[:fumble].nil?
  368. 208 option[:fumble] = term
  369. 208 result = option
  370. 208 result
  371. end
  372. 1 def _reduce_11(val, _values, result)
  373. 72 option, _, term = val
  374. 72 else: 71 then: 1 raise ParseError unless @dollar && option[:dollar].nil?
  375. 71 option[:dollar] = term
  376. 71 result = option
  377. 71 result
  378. end
  379. 1 def _reduce_12(val, _values, result)
  380. 704 result = val[1]
  381. 704 result
  382. end
  383. 1 def _reduce_13(val, _values, result)
  384. 120 result = Arithmetic::Node::Negative.new(val[1])
  385. 120 result
  386. end
  387. 1 def _reduce_14(val, _values, result)
  388. 92 result = Arithmetic::Node::BinaryOp.new(val[0], :+, val[2])
  389. 92 result
  390. end
  391. 1 def _reduce_15(val, _values, result)
  392. 84 result = Arithmetic::Node::BinaryOp.new(val[0], :-, val[2])
  393. 84 result
  394. end
  395. 1 def _reduce_16(val, _values, result)
  396. 939 else: 934 then: 5 raise ParseError unless @allowed_cmp_op.include?(nil)
  397. 934 result = {}
  398. 934 result
  399. end
  400. 1 def _reduce_17(val, _values, result)
  401. 798 cmp_op, target = val
  402. 798 else: 796 then: 2 raise ParseError unless @allowed_cmp_op.include?(cmp_op)
  403. 796 result = {cmp_op: cmp_op, target: target}
  404. 796 result
  405. end
  406. 1 def _reduce_18(val, _values, result)
  407. 36 cmp_op = val[0]
  408. 36 else: 35 then: 1 raise ParseError unless @question_target
  409. 35 else: 35 then: 0 raise ParseError unless @allowed_cmp_op.include?(cmp_op)
  410. 35 result = {cmp_op: cmp_op, target: "?"}
  411. 35 result
  412. end
  413. 1 def _reduce_19(val, _values, result)
  414. 10 result = Arithmetic::Node::BinaryOp.new(val[0], :+, val[2])
  415. 10 result
  416. end
  417. 1 def _reduce_20(val, _values, result)
  418. 2 result = Arithmetic::Node::BinaryOp.new(val[0], :-, val[2])
  419. 2 result
  420. end
  421. # reduce 21 omitted
  422. 1 def _reduce_22(val, _values, result)
  423. 14 result = Arithmetic::Node::BinaryOp.new(val[0], :*, val[2])
  424. 14 result
  425. end
  426. 1 def _reduce_23(val, _values, result)
  427. 2 divied_class = val[3]
  428. 2 result = divied_class.new(val[0], val[2])
  429. 2 result
  430. end
  431. # reduce 24 omitted
  432. 1 def _reduce_25(val, _values, result)
  433. 2 result = Arithmetic::Node::DivideWithGameSystemDefault
  434. 2 result
  435. end
  436. 1 def _reduce_26(val, _values, result)
  437. result = Arithmetic::Node::DivideWithCeil
  438. result
  439. end
  440. 1 def _reduce_27(val, _values, result)
  441. result = Arithmetic::Node::DivideWithCeil
  442. result
  443. end
  444. 1 def _reduce_28(val, _values, result)
  445. result = Arithmetic::Node::DivideWithRound
  446. result
  447. end
  448. 1 def _reduce_29(val, _values, result)
  449. result = Arithmetic::Node::DivideWithFloor
  450. result
  451. end
  452. 1 def _reduce_30(val, _values, result)
  453. 6 result = val[1]
  454. 6 result
  455. end
  456. 1 def _reduce_31(val, _values, result)
  457. 15 result = Arithmetic::Node::Negative.new(val[1])
  458. 15 result
  459. end
  460. # reduce 32 omitted
  461. 1 def _reduce_33(val, _values, result)
  462. result = val[1]
  463. result
  464. end
  465. 1 def _reduce_34(val, _values, result)
  466. 3076 result = Arithmetic::Node::Number.new(val[0])
  467. 3076 result
  468. end
  469. 1 def _reduce_none(val, _values, result)
  470. val[0]
  471. end
  472. end # class Parser
  473. end # module Command
  474. end # module BCDice

lib/bcdice/common_command.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/common_command/add_dice"
  3. 1 require "bcdice/common_command/barabara_dice"
  4. 1 require "bcdice/common_command/tally_dice"
  5. 1 require "bcdice/common_command/calc"
  6. 1 require "bcdice/common_command/choice"
  7. 1 require "bcdice/common_command/d66_dice"
  8. 1 require "bcdice/common_command/repeat"
  9. 1 require "bcdice/common_command/reroll_dice"
  10. 1 require "bcdice/common_command/upper_dice"
  11. 1 require "bcdice/common_command/version"
  12. 1 module BCDice
  13. 1 module CommonCommand
  14. COMMANDS = [
  15. 1 AddDice,
  16. BarabaraDice,
  17. TallyDice,
  18. Calc,
  19. Choice,
  20. D66Dice,
  21. Repeat,
  22. RerollDice,
  23. UpperDice,
  24. Version,
  25. ].freeze
  26. end
  27. end

lib/bcdice/common_command/add_dice.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/normalize"
  3. 1 require "bcdice/common_command/add_dice/parser"
  4. 1 require "bcdice/common_command/add_dice/randomizer"
  5. 1 module BCDice
  6. 1 module CommonCommand
  7. 1 module AddDice
  8. 1 PREFIX_PATTERN = /[+\-(]*(\d+|D\d+)/.freeze
  9. 1 class << self
  10. 1 def eval(command, game_system, randomizer)
  11. 1843 cmd = Parser.parse(command)
  12. 1843 then: 1164 else: 679 cmd&.eval(game_system, randomizer)
  13. end
  14. end
  15. end
  16. end
  17. end

lib/bcdice/common_command/add_dice/node.rb

98.31% lines covered

91.67% branches covered

236 relevant lines. 232 lines covered and 4 lines missed.
24 total branches, 22 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "singleton"
  3. 1 module BCDice
  4. 1 module CommonCommand
  5. 1 module AddDice
  6. # 加算ロールの構文解析木のノードを格納するモジュール
  7. 1 module Node
  8. # 加算ロールコマンドのノード。
  9. #
  10. # 目標値が設定されていない場合は +lhs+ のみを使用する。
  11. # 目標値が設定されている場合は、+lhs+、+cmp_op+、+rhs+ を使用する。
  12. 1 class Command
  13. # 左辺のノード
  14. # @return [Object]
  15. 1 attr_reader :lhs
  16. # 比較演算子
  17. # @return [Symbol]
  18. 1 attr_reader :cmp_op
  19. # 右辺のノード
  20. # @return [Integer, String]
  21. 1 attr_reader :rhs
  22. # ノードを初期化する
  23. # @param [Object] lhs 左辺のノード
  24. # @param [Symbol] cmp_op 比較演算子
  25. # @param [Integer, String] rhs 右辺のノード
  26. 1 def initialize(secret, lhs, cmp_op = nil, rhs = nil)
  27. 1321 @secret = secret
  28. 1321 @lhs = lhs
  29. 1321 @cmp_op = cmp_op
  30. 1321 @rhs = rhs
  31. end
  32. # 文字列に変換する
  33. # @param game_system [BCDice::Base]
  34. # @return [String]
  35. 1 def expr(game_system)
  36. 1163 then: 811 else: 352 @lhs.expr(game_system) + cmp_op_text + @rhs&.eval(game_system, nil).to_s
  37. end
  38. # ノードのS式を返す
  39. # @return [String]
  40. 1 def s_exp
  41. 61 then: 12 if @cmp_op
  42. 12 "(Command (#{@cmp_op} #{@lhs.s_exp} #{@rhs.s_exp}))"
  43. else: 49 else
  44. 49 "(Command #{@lhs.s_exp})"
  45. end
  46. end
  47. 1 def eval(game_system, randomizer)
  48. 1164 randomizer = Randomizer.new(randomizer, game_system)
  49. 1164 total = @lhs.eval(game_system, randomizer)
  50. interrim_expr =
  51. 1163 else: 433 then: 730 unless randomizer.rand_results.size <= 1 && @lhs.is_a?(Node::DiceRoll)
  52. 730 @lhs.output
  53. end
  54. result =
  55. 1163 then: 811 else: 352 if @cmp_op
  56. 811 rhs = @rhs.eval(game_system, nil)
  57. 811 game_system.check_result(total, randomizer.rand_results, @cmp_op, rhs)
  58. end
  59. 1163 result ||= Result.new
  60. sequence = [
  61. 1163 "(#{expr(game_system)})",
  62. interrim_expr,
  63. total,
  64. then: 1163 else: 0 result&.text
  65. ].compact
  66. 1163 result.tap do |r|
  67. 1163 r.secret = @secret
  68. 1163 r.text = sequence.join(" > ")
  69. end
  70. end
  71. 1 private
  72. # メッセージ中で比較演算子をどのように表示するかを返す
  73. # @return [String]
  74. 1 def cmp_op_text
  75. 1163 case @cmp_op
  76. when: 3 when :'!='
  77. 3 "<>"
  78. when: 3 when :==
  79. 3 "="
  80. else: 1157 else
  81. 1157 @cmp_op.to_s
  82. end
  83. end
  84. end
  85. 1 class UndecidedTarget
  86. 1 include Singleton
  87. 1 def eval(_game_system, _randomizer)
  88. 214 "?"
  89. end
  90. 1 def include_dice?
  91. 110 false
  92. end
  93. 1 def expr(_game_system)
  94. "?"
  95. end
  96. 1 def output
  97. 1 "?"
  98. end
  99. 1 alias s_exp output
  100. end
  101. # 二項演算子のノード
  102. 1 class BinaryOp
  103. # ノードを初期化する
  104. # @param [Object] lhs 左のオペランドのノード
  105. # @param [Symbol] op 演算子
  106. # @param [Object] rhs 右のオペランドのノード
  107. 1 def initialize(lhs, op, rhs)
  108. 294 @lhs = lhs
  109. 294 @op = op
  110. 294 @rhs = rhs
  111. end
  112. # ノードを評価する
  113. #
  114. # 左右のオペランドをそれぞれ再帰的に評価した後で、演算を行う。
  115. #
  116. # @param game_system [BCDice::Base]
  117. # @param randomizer [Randomizer] ランダマイザ
  118. # @return [Integer] 評価結果
  119. 1 def eval(game_system, randomizer)
  120. 250 lhs = @lhs.eval(game_system, randomizer)
  121. 250 rhs = @rhs.eval(game_system, randomizer)
  122. 250 return calc(lhs, rhs, game_system.round_type)
  123. end
  124. # @return [Boolean]
  125. 1 def include_dice?
  126. 266 @lhs.include_dice? || @rhs.include_dice?
  127. end
  128. # 文字列に変換する
  129. # @return [String]
  130. 1 def expr(game_system)
  131. 173 lhs = @lhs.expr(game_system)
  132. 173 rhs = @rhs.expr(game_system)
  133. 173 "#{lhs}#{@op}#{rhs}"
  134. end
  135. # メッセージへの出力を返す
  136. # @return [String]
  137. 1 def output
  138. 212 "#{@lhs.output}#{@op}#{@rhs.output}"
  139. end
  140. # ノードのS式を返す
  141. # @return [String]
  142. 1 def s_exp
  143. 40 "(#{op_for_s_exp} #{@lhs.s_exp} #{@rhs.s_exp})"
  144. end
  145. 1 private
  146. # 演算を行う
  147. # @param lhs [Integer] lhs 左のオペランド
  148. # @param rhs [Integer] 右のオペランド
  149. # @param _round_type [Symbol] ゲームシステムの端数処理設定
  150. # @return [Integer] 演算の結果
  151. 1 def calc(lhs, rhs, _round_type)
  152. 205 lhs.send(@op, rhs)
  153. end
  154. # S式で使う演算子の表現を返す
  155. # @return [String]
  156. 1 def op_for_s_exp
  157. 33 @op
  158. end
  159. end
  160. # 除算ノードの基底クラス
  161. #
  162. # 定数 +ROUNDING_METHOD+ で端数処理方法を示す記号
  163. # ( +'U'+, +'R'+, +''+ ) を定義すること。
  164. # また、除算および端数処理を行う +divide_and_round+ メソッドを実装すること。
  165. 1 class DivideBase < BinaryOp
  166. # ノードを初期化する
  167. # @param [Object] lhs 左のオペランドのノード
  168. # @param [Object] rhs 右のオペランドのノード
  169. 1 def initialize(lhs, rhs)
  170. 55 super(lhs, :/, rhs)
  171. end
  172. # 文字列に変換する
  173. #
  174. # 通常の結果の末尾に、端数処理方法を示す記号を付加する。
  175. #
  176. # @return [String]
  177. 1 def expr(game_system)
  178. 43 "#{super(game_system)}#{rounding_method}"
  179. end
  180. # メッセージへの出力を返す
  181. #
  182. # 通常の結果の末尾に、端数処理方法を示す記号を付加する。
  183. #
  184. # @return [String]
  185. 1 def output
  186. 43 "#{super}#{rounding_method}"
  187. end
  188. 1 private
  189. # 端数処理方法を示す記号を返す
  190. # @return [String]
  191. 1 def rounding_method
  192. 93 self.class::ROUNDING_METHOD
  193. end
  194. # S式で使う演算子の表現を返す
  195. # @return [String]
  196. 1 def op_for_s_exp
  197. 7 "#{@op}#{rounding_method}"
  198. end
  199. # 演算を行う
  200. # @param lhs [Integer] 左のオペランド
  201. # @param rhs [Integer] 右のオペランド
  202. # @param round_type [Symbol] ゲームシステムの端数処理設定
  203. # @return [Integer] 演算の結果
  204. 1 def calc(lhs, rhs, round_type)
  205. 45 then: 1 else: 44 if rhs.zero?
  206. 1 return 1
  207. end
  208. 44 return divide_and_round(lhs, rhs, round_type)
  209. end
  210. # 除算および端数処理を行う
  211. # @param dividend [Integer] 被除数
  212. # @param divisor [Integer] 除数(0以外)
  213. # @param round_type [Symbol] ゲームシステムの端数処理設定
  214. # @return [Integer]
  215. 1 def divide_and_round(dividend, divisor, round_type)
  216. raise NotImplementedError
  217. end
  218. end
  219. # 除算(端数処理はゲームシステム依存)のノード
  220. 1 class DivideWithGameSystemDefault < DivideBase
  221. 1 ROUNDING_METHOD = ""
  222. 1 private
  223. # 除算および端数処理を行う
  224. # @param dividend [Integer] 被除数
  225. # @param divisor [Integer] 除数(0以外)
  226. # @param round_type [Symbol] ゲームシステムの端数処理設定
  227. # @return [Integer]
  228. 1 def divide_and_round(dividend, divisor, round_type)
  229. 20 case round_type
  230. when: 2 when RoundType::CEIL
  231. 2 (dividend.to_f / divisor).ceil
  232. when: 2 when RoundType::ROUND
  233. 2 (dividend.to_f / divisor).round
  234. else: 16 else # RoundType::FLOOR
  235. 16 dividend / divisor
  236. end
  237. end
  238. end
  239. # 除算(切り上げ)のノード
  240. 1 class DivideWithRoundingUp < DivideBase
  241. # 端数処理方法を示す記号
  242. 1 ROUNDING_METHOD = "U"
  243. 1 private
  244. # 除算および端数処理を行う
  245. # @param (see DivideWithGameSystemDefault#divide_and_round)
  246. # @return [Integer]
  247. 1 def divide_and_round(dividend, divisor, _round_type)
  248. 12 (dividend.to_f / divisor).ceil
  249. end
  250. end
  251. # 除算(四捨五入)のノード
  252. 1 class DivideWithRoundingOff < DivideBase
  253. # 端数処理方法を示す記号
  254. 1 ROUNDING_METHOD = "R"
  255. 1 private
  256. # 除算および端数処理を行う
  257. # @param (see DivideWithGameSystemDefault#divide_and_round)
  258. # @return [Integer]
  259. 1 def divide_and_round(dividend, divisor, _round_type)
  260. 10 (dividend.to_f / divisor).round
  261. end
  262. end
  263. # 除算(切り捨て)のノード
  264. 1 class DivideWithRoundingDown < DivideBase
  265. # 端数処理方法を示す記号
  266. 1 ROUNDING_METHOD = "F"
  267. 1 private
  268. # 除算および端数処理を行う
  269. # @param (see DivideWithGameSystemDefault#divide_and_round)
  270. # @return [Integer]
  271. 1 def divide_and_round(dividend, divisor, _round_type)
  272. 2 dividend / divisor
  273. end
  274. end
  275. # 符号反転のノード
  276. 1 class Negate
  277. # 符号反転の対象
  278. # @return [Object]
  279. 1 attr_reader :body
  280. # ノードを初期化する
  281. # @param [Object] body 符号反転の対象
  282. 1 def initialize(body)
  283. 26 @body = body
  284. end
  285. # ノードを評価する
  286. #
  287. # 対象オペランドを再帰的に評価した後、評価結果の符号を反転する。
  288. #
  289. # @param [Randomizer] randomizer ランダマイザ
  290. # @return [Integer] 評価結果
  291. 1 def eval(game_system, randomizer)
  292. 28 -@body.eval(game_system, randomizer)
  293. end
  294. # @return [Boolean]
  295. 1 def include_dice?
  296. 18 @body.include_dice?
  297. end
  298. # 文字列に変換する
  299. # @return [String]
  300. 1 def expr(game_system)
  301. 12 "-#{@body.expr(game_system)}"
  302. end
  303. # メッセージへの出力を返す
  304. # @return [String]
  305. 1 def output
  306. 12 "-#{@body.output}"
  307. end
  308. # ノードのS式を返す
  309. # @return [String]
  310. 1 def s_exp
  311. 2 "(- #{@body.s_exp})"
  312. end
  313. end
  314. # ダイスロールのノード
  315. 1 class DiceRoll
  316. # ノードを初期化する
  317. # @param [Number] times ダイスを振る回数のノード
  318. # @param [Number] sides ダイスの面数のノード
  319. 1 def initialize(times, sides)
  320. 1253 @times = times
  321. 1253 @sides = sides
  322. # ダイスを振った結果の出力
  323. 1253 @text = nil
  324. end
  325. # ノードを評価する(ダイスを振る)
  326. #
  327. # 評価結果は出目の合計値になる。
  328. # 出目はランダマイザに記録される。
  329. #
  330. # @param [Randomizer] randomizer ランダマイザ
  331. # @return [Integer] 評価結果(出目の合計値)
  332. 1 def eval(game_system, randomizer)
  333. 1222 times = @times.eval(game_system, nil)
  334. 1222 sides = eval_sides(game_system)
  335. 1222 dice_list = randomizer.roll(times, sides)
  336. 1221 total = dice_list.sum()
  337. 1221 @text = "#{total}[#{dice_list.join(',')}]"
  338. 1221 return total
  339. end
  340. # @return [Boolean]
  341. 1 def include_dice?
  342. 1257 true
  343. end
  344. # 文字列に変換する
  345. # @return [String]
  346. 1 def expr(game_system)
  347. 1141 times = @times.eval(game_system, nil)
  348. 1141 sides = eval_sides(game_system)
  349. 1141 "#{times}D#{sides}"
  350. end
  351. # メッセージへの出力を返す
  352. # @return [String]
  353. 1 def output
  354. 788 @text
  355. end
  356. # ノードのS式を返す
  357. # @return [String]
  358. 1 def s_exp
  359. 34 "(DiceRoll #{@times.s_exp} #{@sides.s_exp})"
  360. end
  361. 1 private
  362. 1 def eval_sides(game_system)
  363. 2323 @sides.eval(game_system, nil)
  364. end
  365. end
  366. 1 class ImplicitSidesDiceRoll < DiceRoll
  367. # @param [Number] times ダイスを振る回数のノード
  368. 1 def initialize(times)
  369. 26 @times = times
  370. 26 @text = nil
  371. end
  372. # @return [String]
  373. 1 def s_exp
  374. 2 "(ImplicitSidesDiceRoll #{@times.s_exp})"
  375. end
  376. 1 private
  377. 1 def eval_sides(game_system)
  378. 40 game_system.sides_implicit_d
  379. end
  380. end
  381. # フィルタ処理付きダイスロールのノード。
  382. #
  383. # ダイスロール後、条件に従って出目を選択し、和を求める。
  384. 1 class DiceRollWithFilter
  385. # フィルタの構造体
  386. #
  387. # 各フィルタには、あらかじめソートされた出目の配列が渡される。
  388. #
  389. # @!attribute abbr
  390. # @return [Symbol] フィルタの略称
  391. # @!attribute apply
  392. # @return [Proc] フィルタ処理の内容
  393. 1 Filter = Struct.new(:abbr, :apply)
  394. # 大きな出目から複数個取る
  395. 1 KEEP_HIGHEST = Filter.new(
  396. :KH,
  397. 22 lambda { |sorted_values, n| sorted_values.reverse.take(n) }
  398. ).freeze
  399. # 小さな出目から複数個取る
  400. 1 KEEP_LOWEST = Filter.new(
  401. :KL,
  402. 8 lambda { |sorted_values, n| sorted_values.take(n) }
  403. ).freeze
  404. # 大きな出目から複数個除く
  405. 1 DROP_HIGHEST = Filter.new(
  406. :DH,
  407. 5 lambda { |sorted_values, n| sorted_values.reverse.drop(n) }
  408. ).freeze
  409. # 小さな出目から複数個除く
  410. 1 DROP_LOWEST = Filter.new(
  411. :DL,
  412. 5 lambda { |sorted_values, n| sorted_values.drop(n) }
  413. ).freeze
  414. # ノードを初期化する
  415. # @param [Object] times ダイスを振る回数のノード
  416. # @param [Object, :implicit] sides ダイスの面数のノード(暗黙の面数を参照したい場合は `:implicit`)
  417. # @param [Object] n_filtering ダイスを残す/減らす個数のノード
  418. # @param [Filter] filter フィルタ
  419. 1 def initialize(times, sides, n_filtering, filter)
  420. 71 then: 0 else: 71 if sides != :implicit && !sides.respond_to?(:eval)
  421. raise TypeError, "sides must be a Node or :implicit (#{sides.inspect})"
  422. end
  423. 71 @times = times
  424. 71 @sides = sides
  425. 71 @n_filtering = n_filtering
  426. 71 @filter = filter
  427. # ダイスを振った結果の出力
  428. 71 @text = nil
  429. end
  430. # ノードを評価する(ダイスを振り、出目を選択して和を求める)
  431. #
  432. # 評価結果は出目の合計値になる。
  433. # 出目はランダマイザに記録される。
  434. #
  435. # @param [Randomizer] randomizer ランダマイザ
  436. # @return [Integer] 評価結果(出目の合計値)
  437. 1 def eval(game_system, randomizer)
  438. 40 times = @times.eval(game_system, nil)
  439. 40 sides = eval_sides(game_system)
  440. 40 n_filtering = @n_filtering.eval(game_system, nil)
  441. 40 sorted_values = randomizer.roll(times, sides).sort
  442. 40 total = @filter
  443. .apply[sorted_values, n_filtering]
  444. .sum()
  445. 40 @text = "#{total}[#{sorted_values.join(',')}]"
  446. 40 return total
  447. end
  448. # @return [Boolean]
  449. 1 def include_dice?
  450. 71 true
  451. end
  452. # 暗黙の面数を参照するか?
  453. # @return [Boolean]
  454. 1 def implicit_sides?
  455. 107 @sides == :implicit
  456. end
  457. # 文字列に変換する
  458. # @return [String]
  459. 1 def expr(game_system)
  460. 40 times = @times.eval(game_system, nil)
  461. 40 sides = eval_sides(game_system)
  462. 40 n_filtering = @n_filtering.eval(game_system, nil)
  463. 40 "#{times}D#{sides}#{@filter.abbr}#{n_filtering}"
  464. end
  465. # メッセージへの出力を返す
  466. # @return [String]
  467. 1 def output
  468. 40 @text
  469. end
  470. # ノードのS式を返す
  471. # @return [String]
  472. 1 def s_exp
  473. 27 then: 10 else: 17 sides_s_exp = implicit_sides? ? @sides.inspect : @sides.s_exp
  474. 27 "(DiceRollWithFilter #{@times.s_exp} #{sides_s_exp} #{@filter.abbr.inspect} #{@n_filtering.s_exp})"
  475. end
  476. 1 private
  477. # 面数を評価する
  478. # @return [Integer] 指定された面数または暗黙の面数
  479. 1 def eval_sides(game_system)
  480. 80 then: 32 if implicit_sides?
  481. 32 game_system.sides_implicit_d
  482. else: 48 else
  483. 48 @sides.eval(game_system, nil)
  484. end
  485. end
  486. end
  487. # カッコで式をまとめるノード
  488. 1 class Parenthesis
  489. # @param expr [Object] カッコ内のノード
  490. 1 def initialize(expr)
  491. 37 @expr = expr
  492. end
  493. # @param randomizer [Randomizer]
  494. # @return [integer]
  495. 1 def eval(game_system, randomizer)
  496. 32 @expr.eval(game_system, randomizer)
  497. end
  498. # @return [Boolean]
  499. 1 def include_dice?
  500. 35 @expr.include_dice?
  501. end
  502. # @return [String]
  503. 1 def expr(game_system)
  504. 4 "(#{@expr.expr(game_system)})"
  505. end
  506. # @return [String]
  507. 1 def output
  508. 4 "(#{@expr.output})"
  509. end
  510. # @return [String] S式
  511. 1 def s_exp
  512. 5 "(Parenthesis #{@expr.s_exp})"
  513. end
  514. end
  515. # 数値のノード
  516. 1 class Number
  517. # 値
  518. # @return [Integer]
  519. 1 attr_reader :literal
  520. # ノードを初期化する
  521. # @param [Integer] literal 値
  522. 1 def initialize(literal)
  523. 4109 @literal = literal
  524. end
  525. # 符号を反転した結果の数値ノードを返す
  526. # @return [Number]
  527. 1 def negate
  528. Number.new(-@literal)
  529. end
  530. # ノードを評価する
  531. # @return [Integer] 格納している値
  532. 1 def eval(_game_system, _randomizer)
  533. 6534 @literal
  534. end
  535. # @return [Boolean]
  536. 1 def include_dice?
  537. 3835 false
  538. end
  539. # 文字列に変換する
  540. # @return [String]
  541. 1 def expr(_game_system)
  542. 155 @literal.to_s
  543. end
  544. 1 def output
  545. 384 @literal.to_s
  546. end
  547. 1 alias s_exp output
  548. end
  549. end
  550. end
  551. end
  552. end

lib/bcdice/common_command/add_dice/parser.rb

92.74% lines covered

58.82% branches covered

179 relevant lines. 166 lines covered and 13 lines missed.
34 total branches, 20 branches covered and 14 branches missed.
    
  1. #
  2. # DO NOT MODIFY!!!!
  3. # This file is automatically generated by Racc 1.7.3
  4. # from Racc grammar file "parser.y".
  5. #
  6. 1 require 'racc/parser.rb'
  7. 1 require "bcdice/common_command/lexer"
  8. 1 require "bcdice/common_command/add_dice/node"
  9. 1 module BCDice
  10. 1 module CommonCommand
  11. 1 module AddDice
  12. 1 class Parser < Racc::Parser
  13. 1 def self.parse(source)
  14. 2001 new.parse(source)
  15. end
  16. 1 def parse(source)
  17. 2001 @lexer = Lexer.new(source)
  18. 2001 do_parse()
  19. rescue ParseError
  20. 696 nil
  21. end
  22. 1 private
  23. 1 def next_token
  24. 8997 @lexer.next_token
  25. end
  26. # 加減算の右辺が負数である場合に加減算を逆転させる
  27. 1 def expand_negate(op, rhs)
  28. 209 then: 2 else: 207 if rhs.is_a?(Node::Negate)
  29. 2 then: 0 if op == :+
  30. else: 2 return [:-, rhs.body]
  31. 2 then: 2 else: 0 elsif op == :-
  32. 2 return [:+, rhs.body]
  33. end
  34. end
  35. 207 [op, rhs]
  36. end
  37. ##### State transition tables begin ###
  38. 1 racc_action_table = [
  39. 14, 14, 50, 12, 51, 19, 20, 14, 14, 14,
  40. 12, 3, 12, 17, 18, 14, 8, 9, 12, 4,
  41. 13, 13, 28, 8, 9, 8, 9, 13, 13, 13,
  42. 14, 8, 9, 12, 15, 13, 14, 23, 14, 12,
  43. 56, 12, 19, 20, 57, 14, 8, 9, 12, nil,
  44. 13, nil, 8, 9, 8, 9, 13, 14, 13, nil,
  45. 12, 8, 9, 14, 16, 13, -27, -27, 19, 20,
  46. -27, 17, 18, 8, 9, nil, 42, 13, nil, 17,
  47. 18, 40, 39, 13, nil, 38, -28, -28, 40, 39,
  48. -28, nil, 38, 45, 47, 44, 46, 52, 53, 54,
  49. 55 ]
  50. 1 racc_action_check = [
  51. 16, 12, 38, 16, 38, 6, 6, 2, 36, 8,
  52. 2, 0, 8, 27, 27, 9, 16, 16, 9, 1,
  53. 16, 12, 16, 2, 2, 8, 8, 2, 36, 8,
  54. 13, 9, 9, 13, 4, 9, 17, 11, 18, 17,
  55. 50, 18, 29, 29, 51, 19, 13, 13, 19, nil,
  56. 13, nil, 17, 17, 18, 18, 17, 20, 18, nil,
  57. 20, 19, 19, 23, 5, 19, 23, 23, 30, 30,
  58. 23, 25, 25, 20, 20, nil, 25, 20, nil, 5,
  59. 5, 24, 24, 23, nil, 24, 33, 33, 34, 34,
  60. 33, nil, 34, 32, 32, 32, 32, 39, 39, 40,
  61. 40 ]
  62. 1 racc_action_pointer = [
  63. 7, 19, 5, nil, 34, 61, -15, nil, 7, 13,
  64. nil, 32, -1, 28, nil, nil, -2, 34, 36, 43,
  65. 55, nil, nil, 61, 76, 53, nil, -5, nil, 22,
  66. 48, nil, 79, 81, 83, nil, 6, nil, -8, 90,
  67. 92, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  68. 29, 31, nil, nil, nil, nil, nil, nil ]
  69. 1 racc_action_default = [
  70. -3, -41, -41, -4, -41, -1, -9, -12, -41, -41,
  71. -20, -26, -41, -41, -40, 58, -41, -41, -41, -41,
  72. -41, -18, -19, -22, -24, -41, -2, -5, -6, -7,
  73. -8, -10, -13, -21, -41, -25, -37, -30, -41, -41,
  74. -41, -38, -39, -11, -14, -15, -16, -17, -23, -29,
  75. -41, -41, -33, -34, -35, -36, -31, -32 ]
  76. 1 racc_goto_table = [
  77. 24, 5, 21, 22, 29, 30, 35, 1, 2, 26,
  78. 43, 33, 25, 31, 32, 27, 48, 34, nil, nil,
  79. nil, nil, nil, nil, 49 ]
  80. 1 racc_goto_check = [
  81. 9, 3, 6, 6, 5, 5, 11, 1, 2, 4,
  82. 7, 9, 3, 6, 6, 3, 11, 10, nil, nil,
  83. nil, nil, nil, nil, 9 ]
  84. 1 racc_goto_pointer = [
  85. nil, 7, 8, -1, -7, -13, -6, -22, nil, -12,
  86. -6, -18, nil, nil, nil ]
  87. 1 racc_goto_default = [
  88. nil, nil, nil, nil, nil, 6, 7, nil, 10, 11,
  89. nil, nil, 36, 37, 41 ]
  90. 1 racc_reduce_table = [
  91. 0, 0, :racc_error,
  92. 2, 26, :_reduce_1,
  93. 4, 26, :_reduce_2,
  94. 0, 27, :_reduce_3,
  95. 1, 27, :_reduce_4,
  96. 1, 29, :_reduce_none,
  97. 1, 29, :_reduce_6,
  98. 3, 28, :_reduce_7,
  99. 3, 28, :_reduce_8,
  100. 1, 28, :_reduce_none,
  101. 3, 30, :_reduce_10,
  102. 4, 30, :_reduce_11,
  103. 1, 30, :_reduce_none,
  104. 0, 32, :_reduce_13,
  105. 1, 32, :_reduce_14,
  106. 1, 32, :_reduce_15,
  107. 1, 32, :_reduce_16,
  108. 1, 32, :_reduce_17,
  109. 2, 31, :_reduce_18,
  110. 2, 31, :_reduce_19,
  111. 1, 31, :_reduce_none,
  112. 3, 33, :_reduce_21,
  113. 2, 33, :_reduce_22,
  114. 4, 33, :_reduce_23,
  115. 2, 33, :_reduce_24,
  116. 3, 33, :_reduce_25,
  117. 1, 33, :_reduce_none,
  118. 0, 35, :_reduce_27,
  119. 1, 35, :_reduce_28,
  120. 2, 36, :_reduce_29,
  121. 1, 36, :_reduce_30,
  122. 3, 39, :_reduce_31,
  123. 3, 39, :_reduce_32,
  124. 2, 37, :_reduce_33,
  125. 2, 37, :_reduce_34,
  126. 2, 37, :_reduce_35,
  127. 2, 37, :_reduce_36,
  128. 1, 38, :_reduce_none,
  129. 1, 38, :_reduce_none,
  130. 3, 34, :_reduce_39,
  131. 1, 34, :_reduce_40 ]
  132. 1 racc_reduce_n = 41
  133. 1 racc_shift_n = 58
  134. 1 racc_token_table = {
  135. false => 0,
  136. :error => 1,
  137. :NUMBER => 2,
  138. :CMP_OP => 3,
  139. :S => 4,
  140. :D => 5,
  141. :K => 6,
  142. :H => 7,
  143. :L => 8,
  144. :M => 9,
  145. :A => 10,
  146. :X => 11,
  147. :I => 12,
  148. :N => 13,
  149. :U => 14,
  150. :R => 15,
  151. :F => 16,
  152. :C => 17,
  153. :PLUS => 18,
  154. :MINUS => 19,
  155. :ASTERISK => 20,
  156. :SLASH => 21,
  157. :PARENL => 22,
  158. :PARENR => 23,
  159. :QUESTION => 24 }
  160. 1 racc_nt_base = 25
  161. 1 racc_use_result_var = true
  162. Racc_arg = [
  163. 1 racc_action_table,
  164. racc_action_check,
  165. racc_action_default,
  166. racc_action_pointer,
  167. racc_goto_table,
  168. racc_goto_check,
  169. racc_goto_default,
  170. racc_goto_pointer,
  171. racc_nt_base,
  172. racc_reduce_table,
  173. racc_token_table,
  174. racc_shift_n,
  175. racc_reduce_n,
  176. racc_use_result_var ]
  177. 1 then: 1 else: 0 Ractor.make_shareable(Racc_arg) if defined?(Ractor)
  178. 1 Racc_token_to_s_table = [
  179. "$end",
  180. "error",
  181. "NUMBER",
  182. "CMP_OP",
  183. "S",
  184. "D",
  185. "K",
  186. "H",
  187. "L",
  188. "M",
  189. "A",
  190. "X",
  191. "I",
  192. "N",
  193. "U",
  194. "R",
  195. "F",
  196. "C",
  197. "PLUS",
  198. "MINUS",
  199. "ASTERISK",
  200. "SLASH",
  201. "PARENL",
  202. "PARENR",
  203. "QUESTION",
  204. "$start",
  205. "command",
  206. "secret",
  207. "add",
  208. "target",
  209. "mul",
  210. "unary",
  211. "round_type",
  212. "dice",
  213. "term",
  214. "explicit_or_implicit_sides",
  215. "filter",
  216. "filter_type",
  217. "filter_type_with_shorthand",
  218. "filter_shorthand" ]
  219. 1 then: 1 else: 0 Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
  220. 1 Racc_debug_parser = false
  221. ##### State transition tables end #####
  222. # reduce 0 omitted
  223. 1 def _reduce_1(val, _values, result)
  224. 768 secret, lhs = val
  225. 768 else: 494 then: 274 raise ParseError unless lhs.include_dice?
  226. 494 result = Node::Command.new(secret, lhs)
  227. 494 result
  228. end
  229. 1 def _reduce_2(val, _values, result)
  230. 829 secret, lhs, cmp_op, rhs = val
  231. 829 then: 2 else: 827 raise ParseError if !lhs.include_dice? || rhs.include_dice? || cmp_op.nil?
  232. 827 result = Node::Command.new(secret, lhs, cmp_op, rhs)
  233. 827 result
  234. end
  235. 1 def _reduce_3(val, _values, result)
  236. 1967 result = false
  237. 1967 result
  238. end
  239. 1 def _reduce_4(val, _values, result)
  240. 34 result = true
  241. 34 result
  242. end
  243. # reduce 5 omitted
  244. 1 def _reduce_6(val, _values, result)
  245. 110 result = Node::UndecidedTarget.instance
  246. 110 result
  247. end
  248. 1 def _reduce_7(val, _values, result)
  249. 171 lhs = val[0]
  250. 171 op, rhs = expand_negate(:+, val[2])
  251. 171 result = Node::BinaryOp.new(lhs, op, rhs)
  252. 171 result
  253. end
  254. 1 def _reduce_8(val, _values, result)
  255. 38 lhs = val[0]
  256. 38 op, rhs = expand_negate(:-, val[2])
  257. 38 result = Node::BinaryOp.new(lhs, op, rhs)
  258. 38 result
  259. end
  260. # reduce 9 omitted
  261. 1 def _reduce_10(val, _values, result)
  262. 30 lhs = val[0]
  263. 30 rhs = val[2]
  264. 30 result = Node::BinaryOp.new(lhs, :*, rhs)
  265. 30 result
  266. end
  267. 1 def _reduce_11(val, _values, result)
  268. 55 lhs = val[0]
  269. 55 rhs = val[2]
  270. 55 divied_class = val[3]
  271. 55 result = divied_class.new(lhs, rhs)
  272. 55 result
  273. end
  274. # reduce 12 omitted
  275. 1 def _reduce_13(val, _values, result)
  276. 27 result = Node::DivideWithGameSystemDefault
  277. 27 result
  278. end
  279. 1 def _reduce_14(val, _values, result)
  280. 2 result = Node::DivideWithRoundingDown
  281. 2 result
  282. end
  283. 1 def _reduce_15(val, _values, result)
  284. 12 result = Node::DivideWithRoundingUp
  285. 12 result
  286. end
  287. 1 def _reduce_16(val, _values, result)
  288. 2 result = Node::DivideWithRoundingUp
  289. 2 result
  290. end
  291. 1 def _reduce_17(val, _values, result)
  292. 12 result = Node::DivideWithRoundingOff
  293. 12 result
  294. end
  295. 1 def _reduce_18(val, _values, result)
  296. result = val[1]
  297. result
  298. end
  299. 1 def _reduce_19(val, _values, result)
  300. 27 body = val[1]
  301. 27 then: 1 else: 26 result = body.is_a?(Node::Negate) ? body.body : Node::Negate.new(body)
  302. 27 result
  303. end
  304. # reduce 20 omitted
  305. 1 def _reduce_21(val, _values, result)
  306. 1253 times = val[0]
  307. 1253 sides = val[2]
  308. 1253 then: 4 else: 1249 raise ParseError if times.include_dice? || sides.include_dice?
  309. 1249 result = Node::DiceRoll.new(times, sides)
  310. 1249 result
  311. end
  312. 1 def _reduce_22(val, _values, result)
  313. 26 times = val[0]
  314. 26 then: 0 else: 26 raise ParseError if times.include_dice?
  315. 26 result = Node::ImplicitSidesDiceRoll.new(times)
  316. 26 result
  317. end
  318. 1 def _reduce_23(val, _values, result)
  319. 71 times = val[0]
  320. 71 sides = val[2]
  321. 71 filter = val[3][:filter]
  322. 71 n_filtering = val[3][:n_filtering]
  323. 71 then: 0 else: 71 raise ParseError if sides != :implicit && sides.include_dice?
  324. 71 then: 0 else: 71 raise ParseError if times.include_dice? || n_filtering.include_dice?
  325. 71 result = Node::DiceRollWithFilter.new(times, sides, n_filtering, filter)
  326. 71 result
  327. end
  328. 1 def _reduce_24(val, _values, result)
  329. 62 times = Node::Number.new(1)
  330. 62 sides = val[1]
  331. 62 then: 0 else: 62 raise ParseError if sides.include_dice?
  332. 62 then: 58 else: 4 raise ParseError if sides.instance_of?(Node::Number) && sides.literal == 66
  333. 4 result = Node::DiceRoll.new(times, sides)
  334. 4 result
  335. end
  336. 1 def _reduce_25(val, _values, result)
  337. times = Node::Number.new(1)
  338. sides = val[1]
  339. filter = val[2][:filter]
  340. n_filtering = val[2][:n_filtering]
  341. then: 0 else: 0 raise ParseError if sides != :implicit && sides.include_dice?
  342. then: 0 else: 0 raise ParseError if n_filtering.include_dice?
  343. then: 0 else: 0 raise ParseError if sides.instance_of?(Node::Number) && sides.literal == 66
  344. result = Node::DiceRollWithFilter.new(times, sides, n_filtering, filter)
  345. result
  346. end
  347. # reduce 26 omitted
  348. 1 def _reduce_27(val, _values, result)
  349. 29 result = :implicit
  350. 29 result
  351. end
  352. 1 def _reduce_28(val, _values, result)
  353. 43 result = val[0]
  354. 43 result
  355. end
  356. 1 def _reduce_29(val, _values, result)
  357. 29 result = {filter: val[0], n_filtering: val[1]}
  358. 29 result
  359. end
  360. 1 def _reduce_30(val, _values, result)
  361. 42 result = {filter: val[0], n_filtering: Node::Number.new(1)}
  362. 42 result
  363. end
  364. 1 def _reduce_31(val, _values, result)
  365. 14 result = Node::DiceRollWithFilter::KEEP_HIGHEST
  366. 14 result
  367. end
  368. 1 def _reduce_32(val, _values, result)
  369. 9 result = Node::DiceRollWithFilter::KEEP_LOWEST
  370. 9 result
  371. end
  372. 1 def _reduce_33(val, _values, result)
  373. 19 result = Node::DiceRollWithFilter::KEEP_HIGHEST
  374. 19 result
  375. end
  376. 1 def _reduce_34(val, _values, result)
  377. 9 result = Node::DiceRollWithFilter::KEEP_LOWEST
  378. 9 result
  379. end
  380. 1 def _reduce_35(val, _values, result)
  381. 10 result = Node::DiceRollWithFilter::DROP_HIGHEST
  382. 10 result
  383. end
  384. 1 def _reduce_36(val, _values, result)
  385. 10 result = Node::DiceRollWithFilter::DROP_LOWEST
  386. 10 result
  387. end
  388. # reduce 37 omitted
  389. # reduce 38 omitted
  390. 1 def _reduce_39(val, _values, result)
  391. 37 result = Node::Parenthesis.new(val[1])
  392. 37 result
  393. end
  394. 1 def _reduce_40(val, _values, result)
  395. 4005 result = Node::Number.new(val[0])
  396. 4005 result
  397. end
  398. 1 def _reduce_none(val, _values, result)
  399. val[0]
  400. end
  401. end # class Parser
  402. end # module AddDice
  403. end # module CommonCommand
  404. end # module BCDice

lib/bcdice/common_command/add_dice/randomizer.rb

100.0% lines covered

100.0% branches covered

20 relevant lines. 20 lines covered and 0 lines missed.
6 total branches, 6 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module CommonCommand
  4. 1 module AddDice
  5. 1 class Randomizer
  6. 1 attr_reader :rand_results
  7. 1 RandResult = Struct.new(:sides, :value)
  8. # @param rand_source [BCDice::Randomizer]
  9. # @param game_system [BCDice::Base]
  10. 1 def initialize(rand_source, game_system)
  11. 1244 @rand_source = rand_source
  12. 1244 @game_system = game_system
  13. 1244 @rand_results = []
  14. end
  15. # ダイスを振る
  16. # @param times [Integer] ダイス数
  17. # @param sides [Integer] 面数
  18. # @return [Array<Integer>] 出目の配列
  19. 1 def roll(times, sides)
  20. dice_list =
  21. 1262 then: 2 if sides == 66
  22. 6 else: 1260 Array.new(times) { @rand_source.roll_d66(@game_system.d66_sort_type) }
  23. 1260 then: 4 elsif sides == 9 && @game_system.enabled_d9?
  24. 8 Array.new(times) { @rand_source.roll_d9() }
  25. else: 1256 else
  26. 1256 @rand_source.roll_barabara(times, sides)
  27. end
  28. 1261 then: 300 else: 961 dice_list.sort! if @game_system.sort_add_dice?
  29. 13669 rand_results = dice_list.map { |value| RandResult.new(sides, value) }
  30. 1261 @rand_results.concat(rand_results)
  31. 1261 dice_list
  32. end
  33. end
  34. end
  35. end
  36. end

lib/bcdice/common_command/barabara_dice.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/common_command/barabara_dice/parser"
  3. 1 module BCDice
  4. 1 module CommonCommand
  5. 1 module BarabaraDice
  6. 1 PREFIX_PATTERN = /\d+B\d+/.freeze
  7. 1 class << self
  8. 1 def eval(command, game_system, randomizer)
  9. 727 cmd = Parser.parse(command)
  10. 727 then: 128 else: 599 cmd&.eval(game_system, randomizer)
  11. end
  12. end
  13. end
  14. end
  15. end

lib/bcdice/common_command/barabara_dice/node.rb

100.0% lines covered

100.0% branches covered

46 relevant lines. 46 lines covered and 0 lines missed.
8 total branches, 8 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/format"
  3. 1 require "bcdice/common_command/barabara_dice/result"
  4. 1 module BCDice
  5. 1 module CommonCommand
  6. 1 module BarabaraDice
  7. 1 module Node
  8. 1 class Command
  9. 1 def initialize(secret:, notations:, cmp_op:, target_number:)
  10. 128 @secret = secret
  11. 128 @notations = notations
  12. 128 @cmp_op = cmp_op
  13. 128 @target_number = target_number
  14. end
  15. # @param game_system [Base] ゲームシステム
  16. # @param randomizer [Randomizer] ランダマイザ
  17. # @return [Result]
  18. 1 def eval(game_system, randomizer)
  19. 128 round_type = game_system.round_type
  20. 266 notations = @notations.map { |n| n.to_dice(round_type) }
  21. 128 cmp_op = @cmp_op || game_system.default_cmp_op
  22. 128 then: 103 else: 25 target_number = @target_number&.eval(round_type) || game_system.default_target_number
  23. 266 dice_list_list = notations.map { |d| d.roll(randomizer) }
  24. 128 then: 28 else: 100 dice_list_list.map!(&:sort) if game_system.sort_barabara_dice?
  25. 128 dice_list = dice_list_list.flatten
  26. 128 count_of_1 = dice_list.count(1)
  27. 544 then: 117 else: 11 success_num = cmp_op ? dice_list.count { |d| d.send(cmp_op, target_number) } : 0
  28. 128 then: 117 else: 11 success_num_text = "成功数#{success_num}" if cmp_op
  29. sequence = [
  30. 128 "(#{notations.join('+')}#{Format.comparison_operator(cmp_op)}#{target_number})",
  31. dice_list.join(","),
  32. success_num_text,
  33. game_system.grich_text(count_of_1, dice_list.size, success_num)
  34. ].compact
  35. 128 Result.new.tap do |r|
  36. 128 r.secret = @secret
  37. 128 r.text = sequence.join(" > ")
  38. 128 r.last_dice_list_list = dice_list_list
  39. 128 r.last_dice_list = dice_list
  40. 128 r.success_num = success_num
  41. end
  42. end
  43. end
  44. 1 class Notation
  45. # @param times [#eval]
  46. # @param sides [#eval]
  47. 1 def initialize(times, sides)
  48. 138 @times = times
  49. 138 @sides = sides
  50. end
  51. # @param round_type [Symbol]
  52. 1 def to_dice(round_type)
  53. 138 times = @times.eval(round_type)
  54. 138 sides = @sides.eval(round_type)
  55. 138 Dice.new(times, sides)
  56. end
  57. end
  58. 1 class Dice
  59. # @param times [Integer]
  60. # @param sides [Integer]
  61. 1 def initialize(times, sides)
  62. 138 @times = times
  63. 138 @sides = sides
  64. end
  65. # @param randomizer [BCDice::Randomizer]
  66. # @return [Array<Integer>]
  67. 1 def roll(randomizer)
  68. 138 randomizer.roll_barabara(@times, @sides)
  69. end
  70. # @return [String]
  71. 1 def to_s
  72. 138 "#{@times}B#{@sides}"
  73. end
  74. end
  75. end
  76. end
  77. end
  78. end

lib/bcdice/common_command/barabara_dice/parser.rb

87.96% lines covered

50.0% branches covered

108 relevant lines. 95 lines covered and 13 lines missed.
6 total branches, 3 branches covered and 3 branches missed.
    
  1. #
  2. # DO NOT MODIFY!!!!
  3. # This file is automatically generated by Racc 1.7.3
  4. # from Racc grammar file "parser.y".
  5. #
  6. 1 require 'racc/parser.rb'
  7. 1 require "bcdice/common_command/lexer"
  8. 1 require "bcdice/common_command/reroll_dice/node"
  9. 1 require "bcdice/arithmetic/node"
  10. 1 module BCDice
  11. 1 module CommonCommand
  12. 1 module BarabaraDice
  13. 1 class Parser < Racc::Parser
  14. 1 def self.parse(source)
  15. 727 new.parse(source)
  16. end
  17. 1 def parse(source)
  18. 727 @lexer = Lexer.new(source)
  19. 727 do_parse()
  20. rescue ParseError
  21. 599 nil
  22. end
  23. 1 private
  24. 1 def next_token
  25. 1653 @lexer.next_token
  26. end
  27. ##### State transition tables begin ###
  28. 1 racc_action_table = [
  29. 13, 9, 3, 9, 24, 25, 9, 9, 9, 26,
  30. 18, 19, 8, 12, 8, 18, 19, 8, 8, 8,
  31. 9, 4, 9, 38, 36, 37, 39, 18, 19, 18,
  32. 19, 8, 9, 8, 9, 27, 28, 24, 25, 18,
  33. 19, 18, 19, 8, 9, 8, 9, 27, 28, 27,
  34. 28, 18, 19, 18, 19, 8, 10, 8, 14 ]
  35. 1 racc_action_check = [
  36. 5, 2, 0, 8, 15, 15, 13, 14, 12, 15,
  37. 8, 8, 2, 5, 8, 12, 12, 13, 14, 12,
  38. 18, 1, 19, 34, 34, 34, 34, 18, 18, 19,
  39. 19, 18, 24, 19, 25, 16, 16, 21, 21, 24,
  40. 24, 25, 25, 24, 27, 25, 28, 31, 31, 32,
  41. 32, 27, 27, 28, 28, 27, 4, 28, 7 ]
  42. 1 racc_action_pointer = [
  43. -6, 21, -1, nil, 56, -9, nil, 55, 1, nil,
  44. nil, nil, 6, 4, 5, -5, 24, nil, 18, 20,
  45. nil, 28, nil, nil, 30, 32, nil, 42, 44, nil,
  46. nil, 36, 38, nil, 19, nil, nil, nil, nil, nil ]
  47. 1 racc_action_default = [
  48. -2, -25, -25, -3, -25, -4, -7, -25, -25, -24,
  49. 40, -1, -25, -25, -25, -25, -11, -14, -25, -25,
  50. -22, -5, -6, -8, -25, -25, -23, -25, -25, -20,
  51. -21, -9, -10, -12, -15, -13, -16, -17, -18, -19 ]
  52. 1 racc_goto_table = [
  53. 7, 1, 6, 15, 2, 29, 30, 21, 31, 32,
  54. 5, 7, 23, 22, 33, 34, 11, 35 ]
  55. 1 racc_goto_check = [
  56. 7, 1, 6, 5, 2, 9, 9, 5, 8, 8,
  57. 3, 7, 7, 6, 9, 9, 4, 10 ]
  58. 1 racc_goto_pointer = [
  59. nil, 1, 4, 8, 11, -5, 0, -2, -16, -13,
  60. -17 ]
  61. 1 racc_goto_default = [
  62. nil, nil, nil, nil, nil, nil, nil, 20, 16, 17,
  63. nil ]
  64. 1 racc_reduce_table = [
  65. 0, 0, :racc_error,
  66. 3, 24, :_reduce_1,
  67. 0, 25, :_reduce_2,
  68. 1, 25, :_reduce_3,
  69. 0, 27, :_reduce_4,
  70. 2, 27, :_reduce_5,
  71. 3, 26, :_reduce_6,
  72. 1, 26, :_reduce_7,
  73. 3, 29, :_reduce_8,
  74. 3, 28, :_reduce_9,
  75. 3, 28, :_reduce_10,
  76. 1, 28, :_reduce_none,
  77. 3, 31, :_reduce_12,
  78. 4, 31, :_reduce_13,
  79. 1, 31, :_reduce_none,
  80. 0, 33, :_reduce_15,
  81. 1, 33, :_reduce_16,
  82. 1, 33, :_reduce_17,
  83. 1, 33, :_reduce_18,
  84. 1, 33, :_reduce_19,
  85. 2, 32, :_reduce_20,
  86. 2, 32, :_reduce_21,
  87. 1, 32, :_reduce_none,
  88. 3, 30, :_reduce_23,
  89. 1, 30, :_reduce_24 ]
  90. 1 racc_reduce_n = 25
  91. 1 racc_shift_n = 40
  92. 1 racc_token_table = {
  93. false => 0,
  94. :error => 1,
  95. :NUMBER => 2,
  96. :B => 3,
  97. :R => 4,
  98. :U => 5,
  99. :C => 6,
  100. :F => 7,
  101. :S => 8,
  102. :PLUS => 9,
  103. :MINUS => 10,
  104. :ASTERISK => 11,
  105. :SLASH => 12,
  106. :PARENL => 13,
  107. :PARENR => 14,
  108. :BRACKETL => 15,
  109. :BRACKETR => 16,
  110. :LESS => 17,
  111. :GREATER => 18,
  112. :EQUAL => 19,
  113. :NOT => 20,
  114. :AT => 21,
  115. :CMP_OP => 22 }
  116. 1 racc_nt_base = 23
  117. 1 racc_use_result_var = true
  118. Racc_arg = [
  119. 1 racc_action_table,
  120. racc_action_check,
  121. racc_action_default,
  122. racc_action_pointer,
  123. racc_goto_table,
  124. racc_goto_check,
  125. racc_goto_default,
  126. racc_goto_pointer,
  127. racc_nt_base,
  128. racc_reduce_table,
  129. racc_token_table,
  130. racc_shift_n,
  131. racc_reduce_n,
  132. racc_use_result_var ]
  133. 1 then: 1 else: 0 Ractor.make_shareable(Racc_arg) if defined?(Ractor)
  134. 1 Racc_token_to_s_table = [
  135. "$end",
  136. "error",
  137. "NUMBER",
  138. "B",
  139. "R",
  140. "U",
  141. "C",
  142. "F",
  143. "S",
  144. "PLUS",
  145. "MINUS",
  146. "ASTERISK",
  147. "SLASH",
  148. "PARENL",
  149. "PARENR",
  150. "BRACKETL",
  151. "BRACKETR",
  152. "LESS",
  153. "GREATER",
  154. "EQUAL",
  155. "NOT",
  156. "AT",
  157. "CMP_OP",
  158. "$start",
  159. "expr",
  160. "secret",
  161. "notations",
  162. "target",
  163. "add",
  164. "dice",
  165. "term",
  166. "mul",
  167. "unary",
  168. "round_type" ]
  169. 1 then: 1 else: 0 Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
  170. 1 Racc_debug_parser = false
  171. ##### State transition tables end #####
  172. # reduce 0 omitted
  173. 1 def _reduce_1(val, _values, result)
  174. 128 result = Node::Command.new(
  175. secret: val[0],
  176. notations: val[1],
  177. cmp_op: val[2][:cmp_op],
  178. target_number: val[2][:target]
  179. )
  180. 128 result
  181. end
  182. 1 def _reduce_2(val, _values, result)
  183. 709 result = false
  184. 709 result
  185. end
  186. 1 def _reduce_3(val, _values, result)
  187. 18 result = true
  188. 18 result
  189. end
  190. 1 def _reduce_4(val, _values, result)
  191. 25 result = {}
  192. 25 result
  193. end
  194. 1 def _reduce_5(val, _values, result)
  195. 103 cmp_op, target = val
  196. 103 else: 103 then: 0 raise ParseError unless cmp_op
  197. 103 result = {cmp_op: cmp_op, target: target}
  198. 103 result
  199. end
  200. 1 def _reduce_6(val, _values, result)
  201. 10 notations = val[0]
  202. 10 notations.push(val[2])
  203. 10 result = notations
  204. 10 result
  205. end
  206. 1 def _reduce_7(val, _values, result)
  207. 128 result = [val[0]]
  208. 128 result
  209. end
  210. 1 def _reduce_8(val, _values, result)
  211. 138 times = val[0]
  212. 138 sides = val[2]
  213. 138 result = Node::Notation.new(times, sides)
  214. 138 result
  215. end
  216. 1 def _reduce_9(val, _values, result)
  217. 10 result = Arithmetic::Node::BinaryOp.new(val[0], :+, val[2])
  218. 10 result
  219. end
  220. 1 def _reduce_10(val, _values, result)
  221. 2 result = Arithmetic::Node::BinaryOp.new(val[0], :-, val[2])
  222. 2 result
  223. end
  224. # reduce 11 omitted
  225. 1 def _reduce_12(val, _values, result)
  226. 8 result = Arithmetic::Node::BinaryOp.new(val[0], :*, val[2])
  227. 8 result
  228. end
  229. 1 def _reduce_13(val, _values, result)
  230. 2 divied_class = val[3]
  231. 2 result = divied_class.new(val[0], val[2])
  232. 2 result
  233. end
  234. # reduce 14 omitted
  235. 1 def _reduce_15(val, _values, result)
  236. 2 result = Arithmetic::Node::DivideWithGameSystemDefault
  237. 2 result
  238. end
  239. 1 def _reduce_16(val, _values, result)
  240. result = Arithmetic::Node::DivideWithCeil
  241. result
  242. end
  243. 1 def _reduce_17(val, _values, result)
  244. result = Arithmetic::Node::DivideWithCeil
  245. result
  246. end
  247. 1 def _reduce_18(val, _values, result)
  248. result = Arithmetic::Node::DivideWithRound
  249. result
  250. end
  251. 1 def _reduce_19(val, _values, result)
  252. result = Arithmetic::Node::DivideWithFloor
  253. result
  254. end
  255. 1 def _reduce_20(val, _values, result)
  256. result = val[1]
  257. result
  258. end
  259. 1 def _reduce_21(val, _values, result)
  260. result = Arithmetic::Node::Negative.new(val[1])
  261. result
  262. end
  263. # reduce 22 omitted
  264. 1 def _reduce_23(val, _values, result)
  265. 14 result = val[1]
  266. 14 result
  267. end
  268. 1 def _reduce_24(val, _values, result)
  269. 605 result = Arithmetic::Node::Number.new(val[0])
  270. 605 result
  271. end
  272. 1 def _reduce_none(val, _values, result)
  273. val[0]
  274. end
  275. end # class Parser
  276. end # module BarabaraDice
  277. end # module CommonCommand
  278. end # module BCDice

lib/bcdice/common_command/barabara_dice/result.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/result"
  3. 1 module BCDice
  4. 1 module CommonCommand
  5. 1 module BarabaraDice
  6. # バラバラロールの結果を表すクラス
  7. 1 class Result < ::BCDice::Result
  8. # @return [Array<Array<Integer>>] 出目のグループの配列
  9. 1 attr_accessor :last_dice_list_list
  10. # @return [Array<Integer>] すべての出目が格納される配列
  11. 1 attr_accessor :last_dice_list
  12. # @return [Integer] 成功数
  13. 1 attr_accessor :success_num
  14. # @param text [String, nil] 結果の文章
  15. 1 def initialize(text = nil)
  16. 128 super(text)
  17. 128 @last_dice_list_list = []
  18. 128 @last_dice_list = []
  19. 128 @success_num = 0
  20. end
  21. end
  22. end
  23. end
  24. end

lib/bcdice/common_command/calc.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/common_command/calc/parser"
  3. 1 module BCDice
  4. 1 module CommonCommand
  5. 1 module Calc
  6. 1 PREFIX_PATTERN = /C[+\-(]*\d+/.freeze
  7. 1 class << self
  8. 1 def eval(command, game_system, _randomizer)
  9. 582 cmd = Parser.parse(command)
  10. 582 then: 145 else: 437 cmd&.eval(game_system.round_type)
  11. end
  12. end
  13. end
  14. end
  15. end

lib/bcdice/common_command/calc/node.rb

100.0% lines covered

100.0% branches covered

18 relevant lines. 18 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/arithmetic/node"
  3. 1 module BCDice
  4. 1 module CommonCommand
  5. 1 module Calc
  6. 1 module Node
  7. 1 class Command
  8. 1 def initialize(secret:, expr:)
  9. 145 @secret = secret
  10. 145 @expr = expr
  11. end
  12. 1 def eval(round_type)
  13. value =
  14. begin
  15. 145 @expr.eval(round_type)
  16. rescue ZeroDivisionError
  17. 2 "ゼロ除算が発生したため計算できませんでした"
  18. end
  19. output =
  20. 145 then: 37 if @expr.is_a?(Arithmetic::Node::Parenthesis)
  21. 37 @expr.output
  22. else: 108 else
  23. 108 "(#{@expr.output})"
  24. end
  25. 145 Result.new.tap do |r|
  26. 145 r.secret = @secret
  27. 145 r.text = "c#{output} > #{value}"
  28. end
  29. end
  30. end
  31. end
  32. end
  33. end
  34. end

lib/bcdice/common_command/calc/parser.rb

94.25% lines covered

50.0% branches covered

87 relevant lines. 82 lines covered and 5 lines missed.
4 total branches, 2 branches covered and 2 branches missed.
    
  1. #
  2. # DO NOT MODIFY!!!!
  3. # This file is automatically generated by Racc 1.7.3
  4. # from Racc grammar file "parser.y".
  5. #
  6. 1 require 'racc/parser.rb'
  7. 1 require "bcdice/common_command/lexer"
  8. 1 require "bcdice/common_command/calc/node"
  9. 1 require "bcdice/arithmetic/node"
  10. 1 module BCDice
  11. 1 module CommonCommand
  12. 1 module Calc
  13. 1 class Parser < Racc::Parser
  14. 1 def self.parse(source)
  15. 582 new.parse(source)
  16. end
  17. 1 def parse(source)
  18. 582 @lexer = Lexer.new(source)
  19. 582 do_parse()
  20. rescue ParseError
  21. 437 nil
  22. end
  23. 1 private
  24. 1 def next_token
  25. 1223 @lexer.next_token
  26. end
  27. ##### State transition tables begin ###
  28. 1 racc_action_table = [
  29. 14, 3, 14, 15, 16, 4, 10, 11, 10, 11,
  30. 13, 14, 13, 14, 17, 18, 5, 10, 11, 10,
  31. 11, 13, 14, 13, 14, 17, 18, 6, 10, 11,
  32. 10, 11, 13, 14, 13, 14, 17, 18, nil, 10,
  33. 11, 10, 11, 13, nil, 13, 15, 16, nil, nil,
  34. nil, 26, 30, 28, 29, 31 ]
  35. 1 racc_action_check = [
  36. 5, 0, 10, 7, 7, 1, 5, 5, 10, 10,
  37. 5, 11, 10, 13, 8, 8, 2, 11, 11, 13,
  38. 13, 11, 15, 13, 16, 22, 22, 4, 15, 15,
  39. 16, 16, 15, 17, 16, 18, 23, 23, nil, 17,
  40. 17, 18, 18, 17, nil, 18, 21, 21, nil, nil,
  41. nil, 21, 25, 25, 25, 25 ]
  42. 1 racc_action_pointer = [
  43. -6, 5, 11, nil, 27, -2, nil, -5, 4, nil,
  44. 0, 9, nil, 11, nil, 20, 22, 31, 33, nil,
  45. nil, 38, 15, 26, nil, 49, nil, nil, nil, nil,
  46. nil, nil ]
  47. 1 racc_action_default = [
  48. -2, -20, -20, -3, -20, -20, 32, -1, -6, -9,
  49. -20, -20, -17, -20, -19, -20, -20, -20, -20, -15,
  50. -16, -20, -4, -5, -7, -10, -18, -8, -11, -12,
  51. -13, -14 ]
  52. 1 racc_goto_table = [
  53. 7, 1, 19, 20, 22, 23, 2, 27, 21, 24,
  54. 25 ]
  55. 1 racc_goto_check = [
  56. 3, 1, 5, 5, 4, 4, 2, 6, 3, 5,
  57. 5 ]
  58. 1 racc_goto_pointer = [
  59. nil, 1, 6, -5, -11, -8, -18, nil ]
  60. 1 racc_goto_default = [
  61. nil, nil, nil, nil, 8, 9, nil, 12 ]
  62. 1 racc_reduce_table = [
  63. 0, 0, :racc_error,
  64. 3, 15, :_reduce_1,
  65. 0, 16, :_reduce_2,
  66. 1, 16, :_reduce_3,
  67. 3, 17, :_reduce_4,
  68. 3, 17, :_reduce_5,
  69. 1, 17, :_reduce_none,
  70. 3, 18, :_reduce_7,
  71. 4, 18, :_reduce_8,
  72. 1, 18, :_reduce_none,
  73. 0, 20, :_reduce_10,
  74. 1, 20, :_reduce_11,
  75. 1, 20, :_reduce_12,
  76. 1, 20, :_reduce_13,
  77. 1, 20, :_reduce_14,
  78. 2, 19, :_reduce_15,
  79. 2, 19, :_reduce_16,
  80. 1, 19, :_reduce_none,
  81. 3, 21, :_reduce_18,
  82. 1, 21, :_reduce_19 ]
  83. 1 racc_reduce_n = 20
  84. 1 racc_shift_n = 32
  85. 1 racc_token_table = {
  86. false => 0,
  87. :error => 1,
  88. :NUMBER => 2,
  89. :R => 3,
  90. :U => 4,
  91. :C => 5,
  92. :F => 6,
  93. :S => 7,
  94. :PLUS => 8,
  95. :MINUS => 9,
  96. :ASTERISK => 10,
  97. :SLASH => 11,
  98. :PARENL => 12,
  99. :PARENR => 13 }
  100. 1 racc_nt_base = 14
  101. 1 racc_use_result_var = true
  102. Racc_arg = [
  103. 1 racc_action_table,
  104. racc_action_check,
  105. racc_action_default,
  106. racc_action_pointer,
  107. racc_goto_table,
  108. racc_goto_check,
  109. racc_goto_default,
  110. racc_goto_pointer,
  111. racc_nt_base,
  112. racc_reduce_table,
  113. racc_token_table,
  114. racc_shift_n,
  115. racc_reduce_n,
  116. racc_use_result_var ]
  117. 1 then: 1 else: 0 Ractor.make_shareable(Racc_arg) if defined?(Ractor)
  118. 1 Racc_token_to_s_table = [
  119. "$end",
  120. "error",
  121. "NUMBER",
  122. "R",
  123. "U",
  124. "C",
  125. "F",
  126. "S",
  127. "PLUS",
  128. "MINUS",
  129. "ASTERISK",
  130. "SLASH",
  131. "PARENL",
  132. "PARENR",
  133. "$start",
  134. "expr",
  135. "secret",
  136. "add",
  137. "mul",
  138. "unary",
  139. "round_type",
  140. "term" ]
  141. 1 then: 1 else: 0 Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
  142. 1 Racc_debug_parser = false
  143. ##### State transition tables end #####
  144. # reduce 0 omitted
  145. 1 def _reduce_1(val, _values, result)
  146. 145 result = Node::Command.new(
  147. secret: val[0],
  148. expr: val[2]
  149. )
  150. 145 result
  151. end
  152. 1 def _reduce_2(val, _values, result)
  153. 566 result = false
  154. 566 result
  155. end
  156. 1 def _reduce_3(val, _values, result)
  157. 16 result = true
  158. 16 result
  159. end
  160. 1 def _reduce_4(val, _values, result)
  161. 15 result = Arithmetic::Node::BinaryOp.new(val[0], :+, val[2])
  162. 15 result
  163. end
  164. 1 def _reduce_5(val, _values, result)
  165. 17 result = Arithmetic::Node::BinaryOp.new(val[0], :-, val[2])
  166. 17 result
  167. end
  168. # reduce 6 omitted
  169. 1 def _reduce_7(val, _values, result)
  170. 14 result = Arithmetic::Node::BinaryOp.new(val[0], :*, val[2])
  171. 14 result
  172. end
  173. 1 def _reduce_8(val, _values, result)
  174. 31 divied_class = val[3]
  175. 31 result = divied_class.new(val[0], val[2])
  176. 31 result
  177. end
  178. # reduce 9 omitted
  179. 1 def _reduce_10(val, _values, result)
  180. 25 result = Arithmetic::Node::DivideWithGameSystemDefault
  181. 25 result
  182. end
  183. 1 def _reduce_11(val, _values, result)
  184. result = Arithmetic::Node::DivideWithCeil
  185. result
  186. end
  187. 1 def _reduce_12(val, _values, result)
  188. 2 result = Arithmetic::Node::DivideWithCeil
  189. 2 result
  190. end
  191. 1 def _reduce_13(val, _values, result)
  192. 2 result = Arithmetic::Node::DivideWithRound
  193. 2 result
  194. end
  195. 1 def _reduce_14(val, _values, result)
  196. 2 result = Arithmetic::Node::DivideWithFloor
  197. 2 result
  198. end
  199. 1 def _reduce_15(val, _values, result)
  200. result = val[1]
  201. result
  202. end
  203. 1 def _reduce_16(val, _values, result)
  204. 24 result = Arithmetic::Node::Negative.new(val[1])
  205. 24 result
  206. end
  207. # reduce 17 omitted
  208. 1 def _reduce_18(val, _values, result)
  209. 46 result = Arithmetic::Node::Parenthesis.new(val[1])
  210. 46 result
  211. end
  212. 1 def _reduce_19(val, _values, result)
  213. 224 result = Arithmetic::Node::Number.new(val[0])
  214. 224 result
  215. end
  216. 1 def _reduce_none(val, _values, result)
  217. val[0]
  218. end
  219. end # class Parser
  220. end # module Calc
  221. end # module CommonCommand
  222. end # module BCDice

lib/bcdice/common_command/choice.rb

100.0% lines covered

97.14% branches covered

90 relevant lines. 90 lines covered and 0 lines missed.
35 total branches, 34 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "strscan"
  3. 1 module BCDice
  4. 1 module CommonCommand
  5. # チョイスコマンド
  6. #
  7. # 列挙された項目の中から一つを選んで出力する。
  8. #
  9. # フォーマットは以下の通り
  10. # choice[A,B,C,D]
  11. # choice(A,B,C,D)
  12. # choice A B C D
  13. # choice(新クトゥルフ神話TRPG, ソード・ワールド2.5, Dungeons & Dragons)
  14. #
  15. # "choice"の次の文字によって区切り文字が変化する
  16. # "[" -> "," で区切る
  17. # "(" -> "," で区切る
  18. # " " -> /\s+/ にマッチする文字列で区切る
  19. #
  20. # 各項目の前後に空白文字があった場合は除去される
  21. # choice[A, B, C , D ] は choice[A,B,C,D] と等価
  22. #
  23. # 項目が空文字列である場合、その項目は無視する
  24. # choice[A,,C] は choice[A,C] と等価
  25. #
  26. # フォーマットを選ぶことで、項目の文字列に()や,を含めることができる
  27. # choice A,B X,Y -> "A,B" と "X,Y" から選ぶ
  28. # choice(A[], B[], C[]) -> "A[]", "B[]", "C[]" から選ぶ
  29. # choice[A(), B(), C()] -> "A()", "B()", "C()" から選ぶ
  30. #
  31. # "choice"の後に数を指定することで、列挙した要素から重複なしで複数個を選ぶ
  32. # choice2[A,B,C] -> "A", "B", "C" から重複なしで2個選ぶ
  33. #
  34. # 指定したい要素が「AからD」のように連続する項目の場合に「A-D」と省略して記述できる
  35. # 略記の展開はアルファベット1文字もしくは数字の範囲に限り、略記1つを指定したときのみ展開される
  36. # choice[A-D] -> choice[A,B,C,D] と等価
  37. # choice[b-g] -> choice[b,c,d,e,f,g] と等価
  38. # choice[3-7] -> choice[3,4,5,6,7] と等価
  39. # choice[A-D,Z] -> 展開されない。 "A-D", "Z" から選ぶ
  40. # choice[D-A] -> 展開されない。
  41. 1 class Choice
  42. 1 PREFIX_PATTERN = /choice/.freeze
  43. 1 module BlockDelimiter
  44. 1 BRACKET = :bracket # "["
  45. 1 PAREN = :paren # "("
  46. 1 SPACE = :space # /\s/
  47. end
  48. 1 DELIMITER = {
  49. bracket: /,/,
  50. paren: /,/,
  51. space: /\s+/,
  52. }.freeze
  53. 1 DELIMITER_CHAR = {
  54. bracket: ", ",
  55. paren: ", ",
  56. space: " ",
  57. }.freeze
  58. 1 TERMINATION = {
  59. bracket: /\]/,
  60. paren: /\)/,
  61. space: /$/,
  62. }.freeze
  63. 1 SUFFIX = {
  64. bracket: "]",
  65. paren: ")",
  66. space: "",
  67. }.freeze
  68. 1 class << self
  69. # @param command [String]
  70. # @param _game_system [BCDice::Base]
  71. # @param randomizer [Randomizer]
  72. # @return [Result, nil]
  73. 1 def eval(command, _game_system, randomizer)
  74. 437 cmd = parse(command)
  75. 437 then: 22 else: 415 cmd&.roll(randomizer)
  76. end
  77. 1 private
  78. 1 def parse(command)
  79. 437 scanner = StringScanner.new(command)
  80. 437 scanner.skip(/\s+/)
  81. 437 secret = !scanner.scan(/S/i).nil?
  82. 437 else: 35 then: 402 unless scanner.scan(/choice/i)
  83. 402 return nil
  84. end
  85. 35 then: 8 else: 27 takes = scanner.scan(/\d+/)&.to_i || 1
  86. 35 then: 1 else: 34 if takes == 0
  87. 1 return nil
  88. end
  89. type =
  90. 34 case scanner.scan(/\(|\[|\s+/)
  91. when: 23 when "["
  92. 23 BlockDelimiter::BRACKET
  93. when: 6 when "("
  94. 6 BlockDelimiter::PAREN
  95. when: 4 when String
  96. 4 BlockDelimiter::SPACE
  97. else: 1 else
  98. 1 return nil
  99. end
  100. 33 delimiter = DELIMITER[type]
  101. 33 termination = TERMINATION[type]
  102. 33 items = []
  103. 111 body: 45 while (item = scanner.scan_until(delimiter))
  104. 45 items.push(item.delete_suffix(","))
  105. end
  106. 33 last_item = scanner.scan_until(termination)
  107. 33 else: 29 then: 4 unless last_item
  108. 4 return nil
  109. end
  110. 29 items.push(last_item.delete_suffix(SUFFIX[type]))
  111. 29 items = items.map(&:strip).reject(&:empty?)
  112. 29 then: 11 else: 18 if items.size == 1
  113. 11 items = parse_multi_item_shorthand(items.first)
  114. end
  115. 29 then: 7 else: 22 if items.empty? || items.size < takes
  116. 7 return nil
  117. end
  118. 22 new(
  119. secret: secret,
  120. block_delimiter: type,
  121. takes: takes,
  122. items: items
  123. )
  124. end
  125. 1 def parse_multi_item_shorthand(str)
  126. 11 parse_multi_nums_shorthand(str) || parse_multi_chars_shorthand(str) || []
  127. end
  128. 1 def parse_multi_nums_shorthand(str)
  129. 11 m = /^(\d+)-(\d+)$/.match(str)
  130. 11 else: 3 then: 8 unless m
  131. 8 return nil
  132. end
  133. 3 first = m[1].to_i
  134. 3 last = m[2].to_i
  135. 3 then: 1 else: 2 if first > last
  136. 1 return nil
  137. end
  138. 2 return first.upto(last).to_a
  139. end
  140. 1 def parse_multi_chars_shorthand(str)
  141. 9 m = /^([a-z])-([a-z])$/.match(str) || /^([A-Z])-([A-Z])$/.match(str)
  142. 9 else: 7 then: 2 unless m
  143. 2 return nil
  144. end
  145. 7 first = m[1]
  146. 7 last = m[2]
  147. 7 then: 2 else: 5 if first > last
  148. 2 return nil
  149. end
  150. 5 return first.upto(last).to_a
  151. end
  152. end
  153. # @param secret [Boolean]
  154. # @param block_delimiter [BlockDelimiter::BRACKET, BlockDelimiter::PAREN, BlockDelimiter::SPACE]
  155. # @param takes [Integer] 何個チョイスするか
  156. # @param items [Array<String>]
  157. 1 def initialize(secret:, block_delimiter:, takes:, items:)
  158. 22 @secret = secret
  159. 22 @block_delimiter = block_delimiter
  160. 22 @takes = takes
  161. 22 @items = items
  162. end
  163. # @param randomizer [Randomizer]
  164. # @return [Result]
  165. 1 def roll(randomizer)
  166. 22 then: 1 else: 21 if @items.size > 100
  167. 1 return Result.new("項目数は100以下としてください")
  168. end
  169. 21 items = @items.dup
  170. 21 chosens = []
  171. 21 @takes.times do
  172. 28 index = randomizer.roll_index(items.size)
  173. 28 chosens << items.delete_at(index)
  174. end
  175. 21 Result.new.tap do |r|
  176. 21 chosen = chosens.join(DELIMITER_CHAR[@block_delimiter])
  177. 21 r.secret = @secret
  178. 21 r.text = "(#{expr()}) > #{chosen}"
  179. end
  180. end
  181. 1 def expr
  182. 21 then: 16 else: 5 takes = @takes == 1 ? nil : @takes
  183. 21 else: 0 case @block_delimiter
  184. when: 4 when BlockDelimiter::SPACE
  185. 4 "choice#{takes} #{@items.join(' ')}"
  186. when: 13 when BlockDelimiter::BRACKET
  187. 13 "choice#{takes}[#{@items.join(',')}]"
  188. when: 4 when BlockDelimiter::PAREN
  189. 4 "choice#{takes}(#{@items.join(',')})"
  190. end
  191. end
  192. end
  193. end
  194. end

lib/bcdice/common_command/d66_dice.rb

100.0% lines covered

100.0% branches covered

35 relevant lines. 35 lines covered and 0 lines missed.
11 total branches, 11 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module CommonCommand
  4. 1 class D66Dice
  5. 1 PREFIX_PATTERN = /D66/.freeze
  6. 1 class << self
  7. # @param command [String]
  8. # @param game_system [BCDice::Base]
  9. # @param randomizer [Randomizer]
  10. # @return [Result, nil]
  11. 1 def eval(command, game_system, randomizer)
  12. 415 cmd = parse(command, game_system)
  13. 415 then: 58 else: 357 cmd&.eval(randomizer)
  14. end
  15. 1 private
  16. 1 def parse(command, game_system)
  17. 415 command = command.split(" ", 2).first
  18. 415 m = /^(S)?D66([ANSD])?$/i.match(command.upcase)
  19. 415 else: 58 then: 357 return nil unless m
  20. 58 new(
  21. secret: !m[1].nil?,
  22. sort_type: sort_type_from_suffix(m[2]) || game_system.d66_sort_type,
  23. suffix: m[2]
  24. )
  25. end
  26. 1 def sort_type_from_suffix(suffix)
  27. 58 else: 50 case suffix
  28. when: 4 when "A", "S"
  29. 4 D66SortType::ASC
  30. when: 2 when "D"
  31. 2 D66SortType::DESC
  32. when: 2 when "N"
  33. 2 D66SortType::NO_SORT
  34. end
  35. end
  36. end
  37. # @param secret [Boolean]
  38. # @param sort_type [Symbol]
  39. # @param suffix [String, nil]
  40. 1 def initialize(secret:, sort_type:, suffix:)
  41. 58 @secret = secret
  42. 58 @sort_type = sort_type
  43. 58 @suffix = suffix
  44. end
  45. # @param randomizer [Randomizer]
  46. # @return [Result]
  47. 1 def eval(randomizer)
  48. 58 value = roll(randomizer)
  49. 58 Result.new.tap do |r|
  50. 58 r.secret = @secret
  51. 58 r.text = "(D66#{@suffix}) > #{value}"
  52. end
  53. end
  54. 1 private
  55. 1 def roll(randomizer)
  56. 174 dice_list = Array.new(2) { randomizer.roll_once(6) }
  57. 58 else: 40 case @sort_type
  58. when: 16 when D66SortType::ASC
  59. 16 dice_list.sort!
  60. when: 2 when D66SortType::DESC
  61. 2 dice_list.sort!.reverse!
  62. end
  63. 58 return dice_list[0] * 10 + dice_list[1]
  64. end
  65. end
  66. end
  67. end

lib/bcdice/common_command/lexer.rb

100.0% lines covered

100.0% branches covered

20 relevant lines. 20 lines covered and 0 lines missed.
6 total branches, 6 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "strscan"
  3. 1 require "bcdice/normalize"
  4. 1 module BCDice
  5. 1 module CommonCommand
  6. 1 class Lexer
  7. 1 SYMBOLS = {
  8. "+" => :PLUS,
  9. "-" => :MINUS,
  10. "*" => :ASTERISK,
  11. "/" => :SLASH,
  12. "(" => :PARENL,
  13. ")" => :PARENR,
  14. "[" => :BRACKETL,
  15. "]" => :BRACKETR,
  16. "?" => :QUESTION,
  17. "@" => :AT,
  18. }.freeze
  19. 1 def initialize(source)
  20. # sourceが空文字だとString#splitが空になる
  21. 8043 source = source.split(" ", 2).first || ""
  22. 8043 @scanner = StringScanner.new(source)
  23. end
  24. 1 def next_token
  25. 24978 then: 5329 else: 19649 return [false, "$"] if @scanner.eos?
  26. 19649 then: 9864 if (number = @scanner.scan(/\d+/))
  27. 9864 else: 9785 [:NUMBER, number.to_i]
  28. 9785 then: 1005 elsif (cmp_op = @scanner.scan(/[<>!=]+/))
  29. 1005 [:CMP_OP, Normalize.comparison_operator(cmp_op)]
  30. else: 8780 else
  31. 8780 char = @scanner.getch.upcase
  32. 8780 type = SYMBOLS[char] || char.to_sym
  33. 8780 [type, char]
  34. end
  35. end
  36. 1 def source
  37. 82 @scanner.string
  38. end
  39. end
  40. end
  41. end

lib/bcdice/common_command/repeat.rb

100.0% lines covered

100.0% branches covered

51 relevant lines. 51 lines covered and 0 lines missed.
16 total branches, 16 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "strscan"
  3. 1 module BCDice
  4. 1 module CommonCommand
  5. # リピート
  6. #
  7. # 繰り返し回数を指定して、特定のコマンドを複数回実行する
  8. # 例)
  9. # x5 choice[A,B,C,D] #=> `choice[A,B,C,D]`を5回実行する
  10. # rep2 CC<=75 #=> `CC<=75`を2回実行する
  11. # repeat10 2D6+5 #=> `2D6+6`を10回実行する
  12. #
  13. # このコマンドを入れ子させることは許容しない。繰り返し回数の爆発に繋がるためである。
  14. # 以下は実行時にエラーとなる。
  15. # x10 repeat100 100D100
  16. 1 class Repeat
  17. 1 PREFIX_PATTERN = /(repeat|rep|x)\d+/.freeze
  18. 1 REPEAT_LIMIT = 100
  19. 1 class << self
  20. 1 def eval(command, game_system, randomizer)
  21. 357 cmd = parse(command)
  22. 357 then: 14 else: 343 cmd&.roll(game_system, randomizer)
  23. end
  24. 1 private
  25. 1 def parse(command)
  26. 357 scanner = StringScanner.new(command)
  27. 357 secret = !scanner.scan(/s/i).nil?
  28. 357 keyword = scanner.scan(/repeat|rep|x/i)
  29. 357 then: 199 else: 158 repeat_times = scanner.scan(/\d+/)&.to_i
  30. 357 whitespace = scanner.scan(/\s+/)
  31. 357 then: 342 else: 15 if keyword.nil? || repeat_times.nil? || whitespace.nil?
  32. 342 return nil
  33. end
  34. 15 trailer = scanner.post_match
  35. 15 then: 1 else: 14 if trailer.nil? || trailer.empty?
  36. 1 return nil
  37. end
  38. 14 new(
  39. secret: secret,
  40. times: repeat_times,
  41. trailer: trailer
  42. )
  43. end
  44. end
  45. 1 def initialize(secret:, times:, trailer:)
  46. 14 @secret = secret
  47. 14 @times = times
  48. 14 @trailer = trailer
  49. end
  50. 1 def roll(game_system, randomizer)
  51. 14 err = validate()
  52. 14 then: 3 else: 11 return err if err
  53. 11 results = Array.new(@times) do
  54. 233 cmd = game_system.class.new(@trailer)
  55. 233 cmd.randomizer = randomizer
  56. 233 cmd.eval()
  57. end
  58. 10 then: 1 else: 9 if results.count(nil) == @times
  59. 1 return result_with_text("繰り返し対象のコマンドが実行できませんでした (#{@trailer})")
  60. end
  61. 140 text = results.map.with_index(1) { |r, index| "\##{index}\n#{r.text}" }.join("\n\n")
  62. 9 secret = @secret || results.any?(&:secret?)
  63. 9 Result.new.tap do |r|
  64. 9 r.secret = secret
  65. 9 r.text = text
  66. end
  67. end
  68. 1 private
  69. 1 def validate
  70. 14 then: 1 if /\A(repeat|rep|x)\d+/.match?(@trailer)
  71. 1 else: 13 result_with_text("Repeatコマンドの重複はできません")
  72. 13 then: 2 else: 11 elsif @times < 1 || REPEAT_LIMIT < @times
  73. 2 result_with_text("繰り返し回数は1以上、#{REPEAT_LIMIT}以下としてください")
  74. end
  75. end
  76. 1 def result_with_text(text)
  77. 4 Result.new.tap do |r|
  78. 4 r.secret = @secret
  79. 4 r.text = text
  80. end
  81. end
  82. end
  83. end
  84. end

lib/bcdice/common_command/reroll_dice.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/normalize"
  3. 1 require "bcdice/format"
  4. 1 require "bcdice/common_command/reroll_dice/parser"
  5. 1 module BCDice
  6. 1 module CommonCommand
  7. # 個数振り足しダイス
  8. #
  9. # ダイスを振り、条件を満たした出目の個数だけダイスを振り足す。振り足しがなくなるまでこれを繰り返す。
  10. # 成功条件を満たす出目の個数を調べ、成功数を表示する。
  11. #
  12. # 例
  13. # 2R6+1R10[>3]>=5
  14. # 2R6+1R10>=5@>3
  15. #
  16. # 振り足し条件は角カッコかコマンド末尾の @ で指定する。
  17. # [>3] の場合、3より大きい出目が出たら振り足す。
  18. # [3] のように数値のみ指定されている場合、成功条件の比較演算子を流用する。
  19. # 上記の例の時、出目が
  20. # "2R6" -> [5,6] [5,4] [1,3]
  21. # "1R10" -> [9] [1]
  22. # だとすると、 >=5 に該当するダイスは5つなので成功数5となる。
  23. #
  24. # 成功条件が書かれていない場合、成功数0として扱う。
  25. # 振り足し条件が数値のみ指定されている場合、比較演算子は >= が指定されたとして振舞う。
  26. 1 module RerollDice
  27. 1 PREFIX_PATTERN = /\d+R\d+/.freeze
  28. 1 REROLL_LIMIT = 10000
  29. 1 class << self
  30. 1 def eval(command, game_system, randomizer)
  31. 343 cmd = Parser.parse(command)
  32. 343 then: 82 else: 261 cmd&.eval(game_system, randomizer)
  33. end
  34. end
  35. end
  36. end
  37. end

lib/bcdice/common_command/reroll_dice/node.rb

97.8% lines covered

91.3% branches covered

91 relevant lines. 89 lines covered and 2 lines missed.
23 total branches, 21 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module CommonCommand
  4. 1 module RerollDice
  5. 1 module Node
  6. 1 class Command
  7. 1 def initialize(secret:, notations:, source:, cmp_op: nil, target_number: nil, reroll_cmp_op: nil, reroll_threshold: nil)
  8. 82 @secret = secret
  9. 82 @notations = notations
  10. 82 @cmp_op = cmp_op
  11. 82 @target_number_node = target_number
  12. 82 @reroll_cmp_op = reroll_cmp_op
  13. 82 @reroll_threshold_node = reroll_threshold
  14. 82 @source = source
  15. end
  16. 1 def eval(game_system, randomizer)
  17. 82 round_type = game_system.round_type
  18. 82 cmp_op = @cmp_op || game_system.default_cmp_op
  19. 82 reroll_cmp_op = @reroll_cmp_op || cmp_op || :>=
  20. target_number =
  21. 82 then: 23 else: 59 @target_number_node&.eval(round_type) ||
  22. game_system.default_target_number
  23. reroll_threshold =
  24. 82 then: 7 else: 75 @reroll_threshold_node&.eval(round_type) ||
  25. game_system.reroll_dice_reroll_threshold ||
  26. target_number
  27. 82 reroll_condition = RerollCondition.new(reroll_cmp_op, reroll_threshold)
  28. 170 dice_queue = @notations.map { |node| node.to_dice(round_type) }
  29. 170 else: 80 then: 2 unless dice_queue.all? { |d| reroll_condition.valid?(d.sides) }
  30. 2 return result_with_text("#{@source} > 条件が間違っています。2R6>=5 あるいは 2R6[5] のように振り足し目標値を指定してください。")
  31. end
  32. 80 dice_list_list = roll(
  33. dice_queue,
  34. randomizer,
  35. reroll_condition,
  36. game_system.sort_barabara_dice?
  37. )
  38. 80 dice_list = dice_list_list.flatten
  39. # 振り足し分は出目1の個数をカウントしない
  40. 80 one_count = dice_list_list
  41. .take(@notations.size)
  42. .flatten
  43. .count(1)
  44. success_count =
  45. 80 then: 78 if cmp_op
  46. 642 dice_list.count { |val| val.send(cmp_op, target_number) }
  47. else: 2 else
  48. 2 0
  49. end
  50. sequence = [
  51. 80 expr(round_type, reroll_condition, cmp_op, target_number),
  52. 153 dice_list_list.map { |list| list.join(",") }.join(" + "),
  53. "成功数#{success_count}",
  54. game_system.grich_text(one_count, dice_list.size, success_count),
  55. ].compact
  56. 80 result_with_text(sequence.join(" > "))
  57. end
  58. 1 private
  59. # ダイスロールを行う
  60. # @param dice_queue [Array<Dice>] ダイスキュー
  61. # @param randomizer [Randomizer] 乱数生成器
  62. # @param reroll_condition [RerollCondition] 振り足し条件
  63. # @param sort [Boolean] 出目を並び替えるか
  64. # @return [Array<Array<Integer>>]
  65. 1 def roll(dice_queue, randomizer, reroll_condition, sort)
  66. 80 dice_list_list = []
  67. 80 loop_count = 0
  68. 80 body: 153 while !dice_queue.empty? && loop_count < REROLL_LIMIT
  69. 153 dice = dice_queue.shift
  70. 153 loop_count += 1
  71. 153 dice_list = dice.roll(randomizer)
  72. 153 then: 92 else: 61 dice_list.sort! if sort
  73. 153 dice_list_list.push(dice_list)
  74. 723 reroll_count = dice_list.count { |val| reroll_condition.reroll?(val) }
  75. 153 then: 67 else: 86 if reroll_count > 0
  76. 67 dice_queue.push(Dice.new(reroll_count, dice.sides))
  77. end
  78. end
  79. 80 return dice_list_list
  80. end
  81. 1 def expr(round_type, reroll_condition, cmp_op, target_number)
  82. 166 notation = @notations.map { |n| n.to_dice(round_type) }.join("+")
  83. reroll_cmp_op_text =
  84. 80 then: 73 if reroll_condition.cmp_op == cmp_op
  85. 73 ""
  86. else: 7 else
  87. 7 Format.comparison_operator(reroll_condition.cmp_op)
  88. end
  89. 80 cmp_op_text = Format.comparison_operator(cmp_op)
  90. 80 "(#{notation}[#{reroll_cmp_op_text}#{reroll_condition.threshold}]#{cmp_op_text}#{target_number})"
  91. end
  92. 1 def result_with_text(text)
  93. 82 Result.new.tap do |r|
  94. 82 r.secret = @secret
  95. 82 r.text = text
  96. end
  97. end
  98. end
  99. # 振り足し条件を表すクラス。
  100. 1 class RerollCondition
  101. # @return [Symbol] 比較演算子
  102. 1 attr_reader :cmp_op
  103. # @return [Integer] 振り足しの閾値
  104. 1 attr_reader :threshold
  105. # @param cmp_op [Symbol] 比較演算子
  106. # @param threshold [Integer] 振り足しの閾値
  107. 1 def initialize(cmp_op, threshold)
  108. 82 @cmp_op = cmp_op
  109. 82 @threshold = threshold
  110. end
  111. # @param sides [Integer] ダイスの面数
  112. # @return [Boolean] 振り足し条件が妥当か
  113. 1 def valid?(sides)
  114. 88 else: 87 then: 1 return false unless @threshold
  115. 87 case @cmp_op
  116. when: 5 when :<=
  117. 5 @threshold < sides
  118. when: 0 when :<
  119. @threshold <= sides
  120. when: 75 when :>=
  121. 75 @threshold > 1
  122. when: 5 when :>
  123. 5 @threshold >= 1
  124. when: 2 when :'!='
  125. 2 (1..sides).include?(@threshold)
  126. else: 0 else # :==
  127. true
  128. end
  129. end
  130. # @param value [Integer] 出目
  131. # @return [Boolean] 振り足しを行うべきか
  132. 1 def reroll?(value)
  133. 570 value.send(@cmp_op, @threshold)
  134. end
  135. end
  136. 1 class Notation
  137. 1 def initialize(times, sides)
  138. 88 @times = times
  139. 88 @sides = sides
  140. end
  141. 1 def to_dice(round_type)
  142. 174 times = @times.eval(round_type)
  143. 174 sides = @sides.eval(round_type)
  144. 174 Dice.new(times, sides)
  145. end
  146. end
  147. 1 class Dice
  148. 1 attr_reader :times, :sides
  149. 1 def initialize(times, sides)
  150. 241 @times = times
  151. 241 @sides = sides
  152. end
  153. 1 def roll(randomizer)
  154. 153 randomizer.roll_barabara(times, sides)
  155. end
  156. 1 def to_s
  157. 86 "#{times}R#{sides}"
  158. end
  159. end
  160. end
  161. end
  162. end
  163. end

lib/bcdice/common_command/reroll_dice/parser.rb

87.5% lines covered

50.0% branches covered

136 relevant lines. 119 lines covered and 17 lines missed.
10 total branches, 5 branches covered and 5 branches missed.
    
  1. #
  2. # DO NOT MODIFY!!!!
  3. # This file is automatically generated by Racc 1.7.3
  4. # from Racc grammar file "parser.y".
  5. #
  6. 1 require 'racc/parser.rb'
  7. 1 require "bcdice/common_command/lexer"
  8. 1 require "bcdice/common_command/barabara_dice/node"
  9. 1 require "bcdice/arithmetic/node"
  10. 1 module BCDice
  11. 1 module CommonCommand
  12. 1 module RerollDice
  13. 1 class Parser < Racc::Parser
  14. 1 def self.parse(source)
  15. 343 new.parse(source)
  16. end
  17. 1 def parse(source)
  18. 343 @lexer = Lexer.new(source)
  19. 343 do_parse()
  20. rescue ParseError
  21. 261 nil
  22. end
  23. 1 private
  24. 1 def next_token
  25. 819 @lexer.next_token
  26. end
  27. ##### State transition tables begin ###
  28. 1 racc_action_table = [
  29. 9, 3, 9, 9, 9, 15, 20, 21, 20, 21,
  30. 8, 14, 8, 8, 8, 9, 9, 4, 13, 28,
  31. 10, 39, 20, 21, 9, 8, 8, 31, 32, 9,
  32. 20, 21, 33, 16, 8, 20, 21, 9, 24, 8,
  33. 34, 35, 9, 20, 21, 31, 32, 8, 20, 21,
  34. 9, 13, 8, 31, 32, 9, 20, 21, 34, 35,
  35. 8, 20, 21, 9, nil, 8, 34, 35, 9, 20,
  36. 21, 31, 32, 8, 20, 21, 9, nil, 8, nil,
  37. 31, 32, 20, 21, 31, 32, 8, 40, nil, nil,
  38. nil, 47, 51, 49, 50, 52 ]
  39. 1 racc_action_check = [
  40. 14, 0, 24, 2, 15, 5, 14, 14, 24, 24,
  41. 14, 5, 24, 2, 15, 16, 8, 1, 5, 14,
  42. 4, 24, 8, 8, 13, 16, 8, 17, 17, 20,
  43. 13, 13, 17, 7, 13, 20, 20, 21, 11, 20,
  44. 18, 18, 28, 21, 21, 26, 26, 21, 28, 28,
  45. 31, 12, 28, 38, 38, 32, 31, 31, 42, 42,
  46. 31, 32, 32, 34, nil, 32, 43, 43, 35, 34,
  47. 34, 46, 46, 34, 35, 35, 39, nil, 35, nil,
  48. 27, 27, 39, 39, 41, 41, 39, 27, nil, nil,
  49. nil, 41, 45, 45, 45, 45 ]
  50. 1 racc_action_pointer = [
  51. -6, 17, 1, nil, 20, -3, nil, 30, 14, nil,
  52. nil, 18, 30, 22, -2, 2, 13, 19, 30, nil,
  53. 27, 35, nil, nil, 0, nil, 37, 72, 40, nil,
  54. nil, 48, 53, nil, 61, 66, nil, nil, 45, 74,
  55. nil, 76, 48, 56, nil, 89, 63, nil, nil, nil,
  56. nil, nil, nil ]
  57. 1 racc_action_default = [
  58. -4, -31, -31, -5, -31, -6, -13, -31, -31, -30,
  59. 53, -1, -6, -31, -31, -31, -31, -31, -17, -20,
  60. -31, -31, -28, -3, -31, -2, -7, -31, -31, -12,
  61. -14, -31, -31, -29, -31, -31, -26, -27, -10, -31,
  62. -8, -31, -15, -16, -18, -21, -11, -9, -19, -22,
  63. -23, -24, -25 ]
  64. 1 racc_goto_table = [
  65. 17, 7, 11, 36, 37, 26, 27, 1, 6, 25,
  66. 42, 43, 2, 5, 7, 30, 38, 44, 45, 12,
  67. 41, 29, 23, 48, nil, nil, nil, nil, nil, nil,
  68. nil, 46 ]
  69. 1 racc_goto_check = [
  70. 7, 9, 4, 11, 11, 7, 7, 1, 8, 4,
  71. 10, 10, 2, 3, 9, 9, 7, 11, 11, 5,
  72. 7, 8, 6, 12, nil, nil, nil, nil, nil, nil,
  73. nil, 7 ]
  74. 1 racc_goto_pointer = [
  75. nil, 7, 12, 11, -3, 14, 11, -8, 6, -1,
  76. -21, -17, -22 ]
  77. 1 racc_goto_default = [
  78. nil, nil, nil, nil, nil, nil, nil, nil, nil, 22,
  79. 18, 19, nil ]
  80. 1 racc_reduce_table = [
  81. 0, 0, :racc_error,
  82. 3, 23, :_reduce_1,
  83. 4, 23, :_reduce_2,
  84. 4, 23, :_reduce_3,
  85. 0, 24, :_reduce_4,
  86. 1, 24, :_reduce_5,
  87. 0, 26, :_reduce_6,
  88. 2, 26, :_reduce_7,
  89. 3, 27, :_reduce_8,
  90. 4, 27, :_reduce_9,
  91. 2, 28, :_reduce_10,
  92. 3, 28, :_reduce_11,
  93. 3, 25, :_reduce_12,
  94. 1, 25, :_reduce_13,
  95. 3, 30, :_reduce_14,
  96. 3, 29, :_reduce_15,
  97. 3, 29, :_reduce_16,
  98. 1, 29, :_reduce_none,
  99. 3, 32, :_reduce_18,
  100. 4, 32, :_reduce_19,
  101. 1, 32, :_reduce_none,
  102. 0, 34, :_reduce_21,
  103. 1, 34, :_reduce_22,
  104. 1, 34, :_reduce_23,
  105. 1, 34, :_reduce_24,
  106. 1, 34, :_reduce_25,
  107. 2, 33, :_reduce_26,
  108. 2, 33, :_reduce_27,
  109. 1, 33, :_reduce_none,
  110. 3, 31, :_reduce_29,
  111. 1, 31, :_reduce_30 ]
  112. 1 racc_reduce_n = 31
  113. 1 racc_shift_n = 53
  114. 1 racc_token_table = {
  115. false => 0,
  116. :error => 1,
  117. :NUMBER => 2,
  118. :R => 3,
  119. :U => 4,
  120. :C => 5,
  121. :F => 6,
  122. :S => 7,
  123. :PLUS => 8,
  124. :MINUS => 9,
  125. :ASTERISK => 10,
  126. :SLASH => 11,
  127. :PARENL => 12,
  128. :PARENR => 13,
  129. :BRACKETL => 14,
  130. :BRACKETR => 15,
  131. :LESS => 16,
  132. :GREATER => 17,
  133. :EQUAL => 18,
  134. :NOT => 19,
  135. :AT => 20,
  136. :CMP_OP => 21 }
  137. 1 racc_nt_base = 22
  138. 1 racc_use_result_var = true
  139. Racc_arg = [
  140. 1 racc_action_table,
  141. racc_action_check,
  142. racc_action_default,
  143. racc_action_pointer,
  144. racc_goto_table,
  145. racc_goto_check,
  146. racc_goto_default,
  147. racc_goto_pointer,
  148. racc_nt_base,
  149. racc_reduce_table,
  150. racc_token_table,
  151. racc_shift_n,
  152. racc_reduce_n,
  153. racc_use_result_var ]
  154. 1 then: 1 else: 0 Ractor.make_shareable(Racc_arg) if defined?(Ractor)
  155. 1 Racc_token_to_s_table = [
  156. "$end",
  157. "error",
  158. "NUMBER",
  159. "R",
  160. "U",
  161. "C",
  162. "F",
  163. "S",
  164. "PLUS",
  165. "MINUS",
  166. "ASTERISK",
  167. "SLASH",
  168. "PARENL",
  169. "PARENR",
  170. "BRACKETL",
  171. "BRACKETR",
  172. "LESS",
  173. "GREATER",
  174. "EQUAL",
  175. "NOT",
  176. "AT",
  177. "CMP_OP",
  178. "$start",
  179. "expr",
  180. "secret",
  181. "notations",
  182. "target",
  183. "bracket",
  184. "at",
  185. "add",
  186. "dice",
  187. "term",
  188. "mul",
  189. "unary",
  190. "round_type" ]
  191. 1 then: 1 else: 0 Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
  192. 1 Racc_debug_parser = false
  193. ##### State transition tables end #####
  194. # reduce 0 omitted
  195. 1 def _reduce_1(val, _values, result)
  196. 75 result = Node::Command.new(
  197. secret: val[0],
  198. notations: val[1],
  199. cmp_op: val[2][:cmp_op],
  200. target_number: val[2][:target],
  201. source: @lexer.source
  202. )
  203. 75 result
  204. end
  205. 1 def _reduce_2(val, _values, result)
  206. 5 target = val[3]
  207. 5 threshold = val[2]
  208. 5 result = Node::Command.new(
  209. secret: val[0],
  210. notations: val[1],
  211. cmp_op: target[:cmp_op],
  212. target_number: target[:target],
  213. reroll_cmp_op: threshold[:cmp_op],
  214. reroll_threshold: threshold[:threshold],
  215. source: @lexer.source
  216. )
  217. 5 result
  218. end
  219. 1 def _reduce_3(val, _values, result)
  220. 2 target = val[2]
  221. 2 threshold = val[3]
  222. 2 result = Node::Command.new(
  223. secret: val[0],
  224. notations: val[1],
  225. cmp_op: target[:cmp_op],
  226. target_number: target[:target],
  227. reroll_cmp_op: threshold[:cmp_op],
  228. reroll_threshold: threshold[:threshold],
  229. source: @lexer.source
  230. )
  231. 2 result
  232. end
  233. 1 def _reduce_4(val, _values, result)
  234. 332 result = false
  235. 332 result
  236. end
  237. 1 def _reduce_5(val, _values, result)
  238. 11 result = true
  239. 11 result
  240. end
  241. 1 def _reduce_6(val, _values, result)
  242. 59 result = {}
  243. 59 result
  244. end
  245. 1 def _reduce_7(val, _values, result)
  246. 23 cmp_op, target = val
  247. 23 else: 23 then: 0 raise ParseError unless cmp_op
  248. 23 result = {cmp_op: cmp_op, target: target}
  249. 23 result
  250. end
  251. 1 def _reduce_8(val, _values, result)
  252. 2 result = {threshold: val[1]}
  253. 2 result
  254. end
  255. 1 def _reduce_9(val, _values, result)
  256. 3 cmp_op = val[1]
  257. 3 threshold = val[2]
  258. 3 else: 3 then: 0 raise ParseError unless cmp_op
  259. 3 result = {cmp_op: cmp_op, threshold: threshold}
  260. 3 result
  261. end
  262. 1 def _reduce_10(val, _values, result)
  263. result = {threshold: val[1]}
  264. result
  265. end
  266. 1 def _reduce_11(val, _values, result)
  267. 2 cmp_op = val[1]
  268. 2 threshold = val[2]
  269. 2 else: 2 then: 0 raise ParseError unless cmp_op
  270. 2 result = {cmp_op: cmp_op, threshold: threshold}
  271. 2 result
  272. end
  273. 1 def _reduce_12(val, _values, result)
  274. 6 notations = val[0]
  275. 6 notations.push(val[2])
  276. 6 result = notations
  277. 6 result
  278. end
  279. 1 def _reduce_13(val, _values, result)
  280. 82 result = [val[0]]
  281. 82 result
  282. end
  283. 1 def _reduce_14(val, _values, result)
  284. 88 times = val[0]
  285. 88 sides = val[2]
  286. 88 result = Node::Notation.new(times, sides)
  287. 88 result
  288. end
  289. 1 def _reduce_15(val, _values, result)
  290. 3 result = Arithmetic::Node::BinaryOp.new(val[0], :+, val[2])
  291. 3 result
  292. end
  293. 1 def _reduce_16(val, _values, result)
  294. 2 result = Arithmetic::Node::BinaryOp.new(val[0], :-, val[2])
  295. 2 result
  296. end
  297. # reduce 17 omitted
  298. 1 def _reduce_18(val, _values, result)
  299. result = Arithmetic::Node::BinaryOp.new(val[0], :*, val[2])
  300. result
  301. end
  302. 1 def _reduce_19(val, _values, result)
  303. 2 divied_class = val[3]
  304. 2 result = divied_class.new(val[0], val[2])
  305. 2 result
  306. end
  307. # reduce 20 omitted
  308. 1 def _reduce_21(val, _values, result)
  309. 2 result = Arithmetic::Node::DivideWithGameSystemDefault
  310. 2 result
  311. end
  312. 1 def _reduce_22(val, _values, result)
  313. result = Arithmetic::Node::DivideWithCeil
  314. result
  315. end
  316. 1 def _reduce_23(val, _values, result)
  317. result = Arithmetic::Node::DivideWithCeil
  318. result
  319. end
  320. 1 def _reduce_24(val, _values, result)
  321. result = Arithmetic::Node::DivideWithRound
  322. result
  323. end
  324. 1 def _reduce_25(val, _values, result)
  325. result = Arithmetic::Node::DivideWithFloor
  326. result
  327. end
  328. 1 def _reduce_26(val, _values, result)
  329. result = val[1]
  330. result
  331. end
  332. 1 def _reduce_27(val, _values, result)
  333. result = Arithmetic::Node::Negative.new(val[1])
  334. result
  335. end
  336. # reduce 28 omitted
  337. 1 def _reduce_29(val, _values, result)
  338. 2 result = val[1]
  339. 2 result
  340. end
  341. 1 def _reduce_30(val, _values, result)
  342. 318 result = Arithmetic::Node::Number.new(val[0])
  343. 318 result
  344. end
  345. 1 def _reduce_none(val, _values, result)
  346. val[0]
  347. end
  348. end # class Parser
  349. end # module RerollDice
  350. end # module CommonCommand
  351. end # module BCDice

lib/bcdice/common_command/tally_dice.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/common_command/tally_dice/parser"
  3. 1 module BCDice
  4. 1 module CommonCommand
  5. # 個数カウントダイスのモジュール
  6. 1 module TallyDice
  7. 1 PREFIX_PATTERN = /\d+T[YZ]\d+/.freeze
  8. 1 class << self
  9. 1 def eval(command, game_system, randomizer)
  10. 599 cmd = Parser.parse(command)
  11. 599 then: 25 else: 574 cmd&.eval(game_system, randomizer)
  12. end
  13. end
  14. end
  15. end
  16. end

lib/bcdice/common_command/tally_dice/node.rb

100.0% lines covered

100.0% branches covered

55 relevant lines. 55 lines covered and 0 lines missed.
10 total branches, 10 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/result"
  3. 1 module BCDice
  4. 1 module CommonCommand
  5. 1 module TallyDice
  6. # 個数カウントダイスを表すノードをまとめるモジュール
  7. 1 module Node
  8. # 個数カウントダイス:コマンドのノード
  9. 1 class Command
  10. # 最大面数
  11. 1 MAX_SIDES = 20
  12. # @param secret [Boolean] シークレットダイスか
  13. # @param notation [Notation] ダイス表記
  14. 1 def initialize(secret:, notation:)
  15. 25 @secret = secret
  16. 25 @notation = notation
  17. end
  18. # @param game_system [Base] ゲームシステム
  19. # @param randomizer [Randomizer] ランダマイザ
  20. # @return [Result, nil]
  21. 1 def eval(game_system, randomizer)
  22. 25 dice = @notation.to_dice(game_system.round_type)
  23. 25 else: 17 then: 8 unless dice.valid?
  24. 8 return nil
  25. end
  26. 17 then: 2 else: 15 if dice.sides > MAX_SIDES
  27. 2 return Result.new("(#{dice}) > 面数は1以上、#{MAX_SIDES}以下としてください")
  28. end
  29. 15 values = dice.roll(randomizer)
  30. 15 then: 2 else: 13 values_str = (game_system.sort_barabara_dice? ? values.sort : values)
  31. .join(",")
  32. # TODO: Ruby 2.7以降のみサポートするようになった場合
  33. # Enumerable#tally で書く
  34. 15 values_count = values
  35. .group_by(&:itself)
  36. .transform_values(&:length)
  37. 15 values_count_strs = (1..dice.sides).map do |v|
  38. 78 count = values_count.fetch(v, 0)
  39. 78 then: 5 else: 73 next nil if count == 0 && !dice.show_zeros?
  40. 73 "[#{v}]×#{values_count.fetch(v, 0)}"
  41. end
  42. sequence = [
  43. 15 "(#{dice})",
  44. values_str,
  45. values_count_strs.compact.join(", "),
  46. ].compact
  47. 15 Result.new.tap do |r|
  48. 15 r.secret = @secret
  49. 15 r.text = sequence.join(" > ")
  50. end
  51. end
  52. end
  53. # 個数カウントダイス:ダイス表記のノード
  54. 1 class Notation
  55. # @return [Integer] 振る回数
  56. 1 attr_reader :times
  57. # @return [Integer] 面数
  58. 1 attr_reader :sides
  59. # @return [Boolean] 個数0を表示するか
  60. 1 attr_reader :show_zeros
  61. # @param times [#eval] 振る回数
  62. # @param sides [#eval] 面数
  63. # @param show_zeros [Boolean] 個数0を表示するか
  64. 1 def initialize(times:, sides:, show_zeros:)
  65. 25 @times = times
  66. 25 @sides = sides
  67. 25 @show_zeros = show_zeros
  68. end
  69. # @param round_type [Symbol] 除算の端数処理方法
  70. # @return [Dice]
  71. 1 def to_dice(round_type)
  72. 25 times = @times.eval(round_type)
  73. 25 sides = @sides.eval(round_type)
  74. 25 Dice.new(times: times, sides: sides, show_zeros: @show_zeros)
  75. end
  76. end
  77. # 個数カウントダイス:ダイスのノード
  78. 1 class Dice
  79. # @return [Integer] 振る回数
  80. 1 attr_reader :times
  81. # @return [Integer] 面数
  82. 1 attr_reader :sides
  83. # @return [Boolean] 個数0を表示するか
  84. 1 attr_reader :show_zeros
  85. 1 alias show_zeros? show_zeros
  86. # @param times [Integer] 振る回数
  87. # @param sides [Integer] 面数
  88. 1 def initialize(times:, sides:, show_zeros:)
  89. 25 @times = times
  90. 25 @sides = sides
  91. 25 @show_zeros = show_zeros
  92. end
  93. # @return [Boolean] ダイスとして有効(振る回数、面数ともに正の数)か
  94. 1 def valid?
  95. 25 @times > 0 && @sides > 0
  96. end
  97. # ダイスを振る
  98. # @param randomizer [BCDice::Randomizer] ランダマイザ
  99. # @return [Array<Integer>] 出目の配列
  100. 1 def roll(randomizer)
  101. 15 randomizer.roll_barabara(@times, @sides)
  102. end
  103. # @return [String]
  104. 1 def to_s
  105. 17 then: 8 else: 9 show_zeros_symbol = @show_zeros ? "Z" : "Y"
  106. 17 "#{@times}T#{show_zeros_symbol}#{@sides}"
  107. end
  108. end
  109. end
  110. end
  111. end
  112. end

lib/bcdice/common_command/tally_dice/parser.rb

88.54% lines covered

50.0% branches covered

96 relevant lines. 85 lines covered and 11 lines missed.
4 total branches, 2 branches covered and 2 branches missed.
    
  1. #
  2. # DO NOT MODIFY!!!!
  3. # This file is automatically generated by Racc 1.7.3
  4. # from Racc grammar file "parser.y".
  5. #
  6. 1 require 'racc/parser.rb'
  7. 1 require "bcdice/common_command/lexer"
  8. 1 require "bcdice/common_command/tally_dice/node"
  9. 1 require "bcdice/arithmetic/node"
  10. 1 module BCDice
  11. 1 module CommonCommand
  12. 1 module TallyDice
  13. 1 class Parser < Racc::Parser
  14. 1 def self.parse(source)
  15. 599 new.parse(source)
  16. end
  17. 1 def parse(source)
  18. 599 @lexer = Lexer.new(source)
  19. 599 do_parse()
  20. rescue ParseError
  21. 574 nil
  22. end
  23. 1 private
  24. 1 def next_token
  25. 972 @lexer.next_token
  26. end
  27. ##### State transition tables begin ###
  28. 1 racc_action_table = [
  29. 8, 8, 18, 19, 20, 21, 8, 8, 8, 22,
  30. 14, 15, 3, 7, 7, 14, 15, 14, 15, 7,
  31. 7, 7, 8, 4, 8, 35, 33, 34, 36, 8,
  32. 9, 14, 15, 14, 15, 7, 8, 7, 14, 15,
  33. 23, 24, 7, 23, 24, 14, 15, 23, 24, 7,
  34. 10 ]
  35. 1 racc_action_check = [
  36. 2, 7, 10, 10, 11, 11, 14, 17, 15, 11,
  37. 7, 7, 0, 2, 7, 14, 14, 15, 15, 14,
  38. 17, 15, 20, 1, 21, 31, 31, 31, 31, 23,
  39. 4, 20, 20, 21, 21, 20, 24, 21, 23, 23,
  40. 12, 12, 23, 28, 28, 24, 24, 29, 29, 24,
  41. 6 ]
  42. 1 racc_action_pointer = [
  43. 2, 23, -2, nil, 30, nil, 47, -1, nil, nil,
  44. -2, -7, 27, nil, 4, 6, nil, 5, nil, nil,
  45. 20, 22, nil, 27, 34, nil, nil, nil, 30, 34,
  46. nil, 19, nil, nil, nil, nil, nil ]
  47. 1 racc_action_default = [
  48. -2, -23, -23, -3, -23, -1, -23, -23, -22, 37,
  49. -23, -23, -9, -12, -23, -23, -20, -23, -5, -6,
  50. -23, -23, -21, -23, -23, -18, -19, -4, -7, -8,
  51. -10, -13, -11, -14, -15, -16, -17 ]
  52. 1 racc_goto_table = [
  53. 6, 25, 26, 12, 1, 2, 5, 17, 11, 32,
  54. 30, 31, nil, nil, nil, 27, 28, 29 ]
  55. 1 racc_goto_check = [
  56. 4, 8, 8, 7, 1, 2, 3, 5, 6, 9,
  57. 8, 8, nil, nil, nil, 4, 7, 7 ]
  58. 1 racc_goto_pointer = [
  59. nil, 4, 5, 4, -2, -3, 1, -4, -13, -22 ]
  60. 1 racc_goto_default = [
  61. nil, nil, nil, nil, 16, nil, nil, nil, 13, nil ]
  62. 1 racc_reduce_table = [
  63. 0, 0, :racc_error,
  64. 2, 18, :_reduce_1,
  65. 0, 19, :_reduce_2,
  66. 1, 19, :_reduce_3,
  67. 4, 20, :_reduce_4,
  68. 1, 22, :_reduce_5,
  69. 1, 22, :_reduce_6,
  70. 3, 23, :_reduce_7,
  71. 3, 23, :_reduce_8,
  72. 1, 23, :_reduce_none,
  73. 3, 24, :_reduce_10,
  74. 4, 24, :_reduce_11,
  75. 1, 24, :_reduce_none,
  76. 0, 26, :_reduce_13,
  77. 1, 26, :_reduce_14,
  78. 1, 26, :_reduce_15,
  79. 1, 26, :_reduce_16,
  80. 1, 26, :_reduce_17,
  81. 2, 25, :_reduce_18,
  82. 2, 25, :_reduce_19,
  83. 1, 25, :_reduce_none,
  84. 3, 21, :_reduce_21,
  85. 1, 21, :_reduce_22 ]
  86. 1 racc_reduce_n = 23
  87. 1 racc_shift_n = 37
  88. 1 racc_token_table = {
  89. false => 0,
  90. :error => 1,
  91. :NUMBER => 2,
  92. :T => 3,
  93. :Y => 4,
  94. :Z => 5,
  95. :R => 6,
  96. :U => 7,
  97. :C => 8,
  98. :F => 9,
  99. :S => 10,
  100. :PLUS => 11,
  101. :MINUS => 12,
  102. :ASTERISK => 13,
  103. :SLASH => 14,
  104. :PARENL => 15,
  105. :PARENR => 16 }
  106. 1 racc_nt_base = 17
  107. 1 racc_use_result_var = true
  108. Racc_arg = [
  109. 1 racc_action_table,
  110. racc_action_check,
  111. racc_action_default,
  112. racc_action_pointer,
  113. racc_goto_table,
  114. racc_goto_check,
  115. racc_goto_default,
  116. racc_goto_pointer,
  117. racc_nt_base,
  118. racc_reduce_table,
  119. racc_token_table,
  120. racc_shift_n,
  121. racc_reduce_n,
  122. racc_use_result_var ]
  123. 1 then: 1 else: 0 Ractor.make_shareable(Racc_arg) if defined?(Ractor)
  124. 1 Racc_token_to_s_table = [
  125. "$end",
  126. "error",
  127. "NUMBER",
  128. "T",
  129. "Y",
  130. "Z",
  131. "R",
  132. "U",
  133. "C",
  134. "F",
  135. "S",
  136. "PLUS",
  137. "MINUS",
  138. "ASTERISK",
  139. "SLASH",
  140. "PARENL",
  141. "PARENR",
  142. "$start",
  143. "expr",
  144. "secret",
  145. "notation",
  146. "term",
  147. "show_zeros",
  148. "add",
  149. "mul",
  150. "unary",
  151. "round_type" ]
  152. 1 then: 1 else: 0 Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
  153. 1 Racc_debug_parser = false
  154. ##### State transition tables end #####
  155. # reduce 0 omitted
  156. 1 def _reduce_1(val, _values, result)
  157. 25 result = Node::Command.new(
  158. secret: val[0],
  159. notation: val[1]
  160. )
  161. 25 result
  162. end
  163. 1 def _reduce_2(val, _values, result)
  164. 583 result = false
  165. 583 result
  166. end
  167. 1 def _reduce_3(val, _values, result)
  168. 16 result = true
  169. 16 result
  170. end
  171. 1 def _reduce_4(val, _values, result)
  172. 25 result = Node::Notation.new(
  173. times: val[0],
  174. sides: val[3],
  175. show_zeros: val[2]
  176. )
  177. 25 result
  178. end
  179. 1 def _reduce_5(val, _values, result)
  180. 13 result = false
  181. 13 result
  182. end
  183. 1 def _reduce_6(val, _values, result)
  184. 12 result = true
  185. 12 result
  186. end
  187. 1 def _reduce_7(val, _values, result)
  188. 10 result = Arithmetic::Node::BinaryOp.new(val[0], :+, val[2])
  189. 10 result
  190. end
  191. 1 def _reduce_8(val, _values, result)
  192. 4 result = Arithmetic::Node::BinaryOp.new(val[0], :-, val[2])
  193. 4 result
  194. end
  195. # reduce 9 omitted
  196. 1 def _reduce_10(val, _values, result)
  197. 4 result = Arithmetic::Node::BinaryOp.new(val[0], :*, val[2])
  198. 4 result
  199. end
  200. 1 def _reduce_11(val, _values, result)
  201. 6 divied_class = val[3]
  202. 6 result = divied_class.new(val[0], val[2])
  203. 6 result
  204. end
  205. # reduce 12 omitted
  206. 1 def _reduce_13(val, _values, result)
  207. 2 result = Arithmetic::Node::DivideWithGameSystemDefault
  208. 2 result
  209. end
  210. 1 def _reduce_14(val, _values, result)
  211. result = Arithmetic::Node::DivideWithCeil
  212. result
  213. end
  214. 1 def _reduce_15(val, _values, result)
  215. 4 result = Arithmetic::Node::DivideWithCeil
  216. 4 result
  217. end
  218. 1 def _reduce_16(val, _values, result)
  219. result = Arithmetic::Node::DivideWithRound
  220. result
  221. end
  222. 1 def _reduce_17(val, _values, result)
  223. result = Arithmetic::Node::DivideWithFloor
  224. result
  225. end
  226. 1 def _reduce_18(val, _values, result)
  227. result = val[1]
  228. result
  229. end
  230. 1 def _reduce_19(val, _values, result)
  231. result = Arithmetic::Node::Negative.new(val[1])
  232. result
  233. end
  234. # reduce 20 omitted
  235. 1 def _reduce_21(val, _values, result)
  236. 12 result = val[1]
  237. 12 result
  238. end
  239. 1 def _reduce_22(val, _values, result)
  240. 253 result = Arithmetic::Node::Number.new(val[0])
  241. 253 result
  242. end
  243. 1 def _reduce_none(val, _values, result)
  244. val[0]
  245. end
  246. end # class Parser
  247. end # module TallyDice
  248. end # module CommonCommand
  249. end # module BCDice

lib/bcdice/common_command/upper_dice.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/common_command/upper_dice/parser"
  3. 1 module BCDice
  4. 1 module CommonCommand
  5. # 上方無限ロール
  6. #
  7. # ダイスを1つ振る、その出目が閾値より大きければダイスを振り足すのを閾値未満の出目が出るまで繰り返す。
  8. # これを指定したダイス数だけおこない、それぞれのダイスの合計値を求める。
  9. # それらと目標値を比較し、成功した数を表示する。
  10. #
  11. # フォーマットは以下の通り
  12. # 2U4+1U6[4]>=6
  13. # 2U4+1U6>=6@4
  14. #
  15. # 閾値は角カッコで指定するか、コマンドの末尾に @6 のように指定する。
  16. # 閾値の指定が重複した場合、角カッコが優先される。
  17. # この時、出目が
  18. # "2U4" -> 3[3], 10[4,4,2]
  19. # "1U6" -> 6[4,2]
  20. # だとすると、 >=6 に該当するダイスは2つなので成功数2となる。
  21. #
  22. # 2U4[4]+10>=6 のように修正値を指定できる。修正値は全てのダイスに補正を加え、以下のようになる。
  23. # "2U4" -> 3[3]+10=13, 10[4,4,2]+10=20
  24. #
  25. # 比較演算子が書かれていない場合、ダイスの最大値と全ダイスの合計値が出力される。
  26. # 全ダイスの合計値には補正値が1回だけ適用される
  27. # 2U4[4]+10
  28. # "2U4" -> 3[3]+10=13, 10[4,4,2]+10=20
  29. # 最大値:20
  30. # 合計値:23 = 3[3]+10[4,4,2]+10
  31. 1 module UpperDice
  32. 1 PREFIX_PATTERN = /\d+U\d+/.freeze
  33. 1 class << self
  34. # @param command [String]
  35. # @param game_system [BCDice::Base]
  36. # @param randomizer [BCDice::Randomizer]
  37. # @return [UpperDice, nil]
  38. 1 def eval(command, game_system, randomizer)
  39. 261 cmd = Parser.parse(command)
  40. 261 then: 47 else: 214 cmd&.eval(game_system, randomizer)
  41. end
  42. end
  43. end
  44. end
  45. end

lib/bcdice/common_command/upper_dice/node.rb

100.0% lines covered

93.75% branches covered

82 relevant lines. 82 lines covered and 0 lines missed.
16 total branches, 15 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module CommonCommand
  4. 1 module UpperDice
  5. 1 module Node
  6. 1 class Command
  7. # @param secret [Boolean]
  8. # @param notations [Array<Notation>]
  9. # @param modifier [Integer]
  10. # @param cmp_op [Symbol, nil]
  11. # @param target_number [Integer, nil]
  12. # @param reroll_threshold [Integer]
  13. 1 def initialize(secret:, notations:, modifier:, cmp_op:, target_number:, reroll_threshold: nil)
  14. 48 @secret = secret
  15. 48 @notations = notations
  16. 48 @modifier = modifier
  17. 48 @cmp_op = cmp_op
  18. 48 @target_number = target_number
  19. 48 @reroll_threshold = reroll_threshold
  20. end
  21. # 上方無限ロールを実行する
  22. #
  23. # @param randomizer [Randomizer]
  24. # @return [Result, nil]
  25. 1 def eval(game_system, randomizer)
  26. 47 round_type = game_system.round_type
  27. 100 dice_list = @notations.map { |n| n.to_dice(round_type) }
  28. 47 then: 15 else: 32 reroll_threshold = @reroll_threshold&.eval(round_type) || game_system.upper_dice_reroll_threshold || 0
  29. 47 then: 47 else: 0 modifier = @modifier&.eval(round_type) || 0
  30. 47 then: 41 else: 6 target_number = @target_number&.eval(round_type)
  31. 47 expr = expr(dice_list, reroll_threshold, modifier, target_number)
  32. 47 then: 5 else: 42 if reroll_threshold <= 1
  33. 5 return result_with_text("(#{expr}) > 無限ロールの条件がまちがっています")
  34. end
  35. 42 roll_list = dice_list.map do |n|
  36. 45 n.roll(randomizer, reroll_threshold, game_system.sort_barabara_dice?)
  37. end.reduce([], :concat)
  38. result =
  39. 42 then: 36 if @cmp_op
  40. 36 result_success_count(roll_list, modifier, target_number)
  41. else: 6 else
  42. 6 result_max_sum(roll_list, modifier)
  43. end
  44. sequence = [
  45. 42 "(#{expr})",
  46. interlim_expr(roll_list, modifier),
  47. result
  48. ]
  49. 42 result_with_text(sequence.join(" > "))
  50. end
  51. 1 private
  52. 1 def result_success_count(roll_list, modifier, target_number)
  53. 36 success_count = roll_list.count do |e|
  54. 1278 x = e[:sum] + modifier
  55. 1278 x.send(@cmp_op, target_number)
  56. end
  57. 36 "成功数#{success_count}"
  58. end
  59. 1 def result_max_sum(roll_list, modifier)
  60. 27 sum_list = roll_list.map { |e| e[:sum] }
  61. 6 total = sum_list.sum() + modifier
  62. 27 max = sum_list.map { |i| i + modifier }.max
  63. 6 "#{max}/#{total}(最大/合計)"
  64. end
  65. # ダイスロールの結果を文字列に変換する
  66. # 振り足しがなければその数値、振り足しがあれば合計と各ダイスの出目を出力する
  67. #
  68. # @param roll_list [Array<Hash>]
  69. # @param modifier [Integer]
  70. # @return [String]
  71. 1 def interlim_expr(roll_list, modifier)
  72. 42 dice = roll_list.map do |e|
  73. 1299 then: 1078 if e[:list].size == 1
  74. 1078 e[:sum]
  75. else: 221 else
  76. 221 "#{e[:sum]}[#{e[:list].join(',')}]"
  77. end
  78. end.join(",")
  79. 42 dice + Format.modifier(modifier)
  80. end
  81. # パース済みのコマンドを文字列で表示する
  82. #
  83. # @return [String]
  84. 1 def expr(dice_list, reroll_threshold, modifier, target_number)
  85. 47 formated_cmp_op = Format.comparison_operator(@cmp_op)
  86. 47 formated_modifier = Format.modifier(modifier)
  87. 47 "#{dice_list.join('+')}[#{reroll_threshold}]#{formated_modifier}#{formated_cmp_op}#{target_number}"
  88. end
  89. 1 def result_with_text(text)
  90. 47 Result.new.tap do |r|
  91. 47 r.secret = @secret
  92. 47 r.text = text
  93. end
  94. end
  95. end
  96. 1 class Notation
  97. # @param roll_times [Object]
  98. # @param sides [Object]
  99. 1 def initialize(roll_times, sides)
  100. 54 @roll_times = roll_times
  101. 54 @sides = sides
  102. end
  103. # @param round_type [Symbol]
  104. # @return [Dice]
  105. 1 def to_dice(round_type)
  106. 53 roll_times = @roll_times.eval(round_type)
  107. 53 sides = @sides.eval(round_type)
  108. 53 Dice.new(roll_times, sides)
  109. end
  110. end
  111. 1 class Dice
  112. # @param roll_times [Integer]
  113. # @param sides [Integer]
  114. 1 def initialize(roll_times, sides)
  115. 53 @roll_times = roll_times
  116. 53 @sides = sides
  117. end
  118. # @param randomizer [BCDice::Randomizer]
  119. # @param reroll_threshold [Integer]
  120. # @param sort [Boolean]
  121. # @return [Array<Hash>]
  122. 1 def roll(randomizer, reroll_threshold, sort)
  123. 45 ret = Array.new(@roll_times) do
  124. 1299 list = roll_ones(randomizer, reroll_threshold)
  125. 1299 {sum: list.sum(), list: list}
  126. end
  127. 45 then: 29 else: 16 if sort
  128. 1279 ret = ret.sort_by { |e| e[:sum] }
  129. end
  130. 45 return ret
  131. end
  132. # @return [String]
  133. 1 def to_s
  134. 53 "#{@roll_times}U#{@sides}"
  135. end
  136. 1 private
  137. 1 def roll_ones(randomizer, reroll_threshold)
  138. 1299 dice_list = []
  139. 1299 loop do
  140. 1583 value = randomizer.roll_once(@sides)
  141. 1583 dice_list.push(value)
  142. 1583 then: 1299 else: 284 break if value < reroll_threshold
  143. end
  144. 1299 return dice_list
  145. end
  146. end
  147. end
  148. end
  149. end
  150. end

lib/bcdice/common_command/upper_dice/parser.rb

89.13% lines covered

50.0% branches covered

138 relevant lines. 123 lines covered and 15 lines missed.
6 total branches, 3 branches covered and 3 branches missed.
    
  1. #
  2. # DO NOT MODIFY!!!!
  3. # This file is automatically generated by Racc 1.7.3
  4. # from Racc grammar file "parser.y".
  5. #
  6. 1 require 'racc/parser.rb'
  7. 1 require "bcdice/common_command/lexer"
  8. 1 require "bcdice/common_command/upper_dice/node"
  9. 1 require "bcdice/arithmetic/node"
  10. 1 module BCDice
  11. 1 module CommonCommand
  12. 1 module UpperDice
  13. 1 class Parser < Racc::Parser
  14. 1 def self.parse(source)
  15. 261 new.parse(source)
  16. end
  17. 1 def parse(source)
  18. 261 @lexer = Lexer.new(source)
  19. 261 do_parse()
  20. rescue ParseError
  21. 214 nil
  22. end
  23. 1 private
  24. 1 def next_token
  25. 676 @lexer.next_token
  26. end
  27. ##### State transition tables begin ###
  28. 1 racc_action_table = [
  29. 9, 9, 36, 37, 3, 9, 9, 21, 22, 49,
  30. 8, 8, 21, 22, 9, 8, 8, 14, 15, 9,
  31. 21, 22, 4, 16, 8, 21, 22, 9, 10, 8,
  32. 36, 37, 9, 21, 22, 38, 17, 8, 21, 22,
  33. 9, 25, 8, 27, 15, 9, 21, 22, 28, 29,
  34. 8, 21, 22, 9, 44, 8, 39, 40, 9, 21,
  35. 22, 39, 40, 8, 21, 22, 9, 25, 8, 39,
  36. 40, 9, 21, 22, 36, 37, 8, 21, 22, 9,
  37. 17, 8, 39, 40, 9, 21, 22, 39, 40, 8,
  38. 21, 22, 9, nil, 8, 39, 40, nil, 21, 22,
  39. 39, 40, 8, 58, 56, 57, 59, 36, 37 ]
  40. 1 racc_action_check = [
  41. 2, 8, 34, 34, 0, 17, 14, 8, 8, 34,
  42. 2, 8, 14, 14, 15, 17, 14, 5, 5, 16,
  43. 15, 15, 1, 5, 15, 16, 16, 21, 4, 16,
  44. 18, 18, 22, 21, 21, 18, 7, 21, 22, 22,
  45. 25, 11, 22, 12, 12, 27, 25, 25, 13, 13,
  46. 25, 27, 27, 28, 24, 27, 19, 19, 29, 28,
  47. 28, 30, 30, 28, 29, 29, 36, 26, 29, 33,
  48. 33, 37, 36, 36, 45, 45, 36, 37, 37, 39,
  49. 32, 37, 47, 47, 40, 39, 39, 48, 48, 39,
  50. 40, 40, 44, nil, 40, 50, 50, nil, 44, 44,
  51. 51, 51, 44, 53, 53, 53, 53, 54, 54 ]
  52. 1 racc_action_pointer = [
  53. -3, 22, -2, nil, 28, 9, nil, 32, -1, nil,
  54. nil, 20, 35, 40, 4, 12, 17, 3, 22, 46,
  55. nil, 25, 30, nil, 34, 38, 46, 43, 51, 56,
  56. 51, nil, 76, 59, -6, nil, 64, 69, nil, 77,
  57. 82, nil, nil, nil, 90, 66, nil, 72, 77, nil,
  58. 85, 90, nil, 100, 99, nil, nil, nil, nil, nil ]
  59. 1 racc_action_default = [
  60. -4, -35, -35, -5, -35, -6, -17, -35, -35, -34,
  61. 60, -12, -6, -7, -35, -35, -35, -35, -35, -21,
  62. -24, -35, -35, -32, -1, -35, -12, -35, -35, -35,
  63. -8, -16, -32, -9, -35, -18, -35, -35, -33, -35,
  64. -35, -30, -31, -3, -35, -13, -2, -10, -11, -14,
  65. -19, -20, -22, -25, -15, -23, -26, -27, -28, -29 ]
  66. 1 racc_goto_table = [
  67. 18, 30, 33, 41, 42, 24, 6, 1, 34, 2,
  68. 5, 12, 11, 7, 30, 47, 48, 45, 31, 26,
  69. 46, 52, 53, 50, 51, 32, 43, 55, 35, nil,
  70. nil, nil, nil, nil, nil, nil, 54 ]
  71. 1 racc_goto_check = [
  72. 10, 9, 9, 13, 13, 5, 11, 1, 10, 2,
  73. 3, 6, 4, 12, 9, 9, 9, 10, 11, 4,
  74. 5, 13, 13, 9, 9, 12, 7, 14, 12, nil,
  75. nil, nil, nil, nil, nil, nil, 10 ]
  76. 1 racc_goto_pointer = [
  77. nil, 7, 9, 8, 7, -6, 6, 2, nil, -13,
  78. -8, 4, 11, -18, -26 ]
  79. 1 racc_goto_default = [
  80. nil, nil, nil, nil, nil, nil, nil, nil, 13, 19,
  81. nil, nil, 23, 20, nil ]
  82. 1 racc_reduce_table = [
  83. 0, 0, :racc_error,
  84. 4, 23, :_reduce_1,
  85. 5, 23, :_reduce_2,
  86. 5, 23, :_reduce_3,
  87. 0, 24, :_reduce_4,
  88. 1, 24, :_reduce_5,
  89. 0, 26, :_reduce_6,
  90. 1, 26, :_reduce_7,
  91. 2, 30, :_reduce_8,
  92. 2, 30, :_reduce_9,
  93. 3, 30, :_reduce_10,
  94. 3, 30, :_reduce_11,
  95. 0, 27, :_reduce_12,
  96. 2, 27, :_reduce_13,
  97. 3, 28, :_reduce_14,
  98. 2, 29, :_reduce_15,
  99. 3, 25, :_reduce_16,
  100. 1, 25, :_reduce_17,
  101. 3, 33, :_reduce_18,
  102. 3, 32, :_reduce_19,
  103. 3, 32, :_reduce_20,
  104. 1, 32, :_reduce_none,
  105. 3, 31, :_reduce_22,
  106. 4, 31, :_reduce_23,
  107. 1, 31, :_reduce_none,
  108. 0, 36, :_reduce_25,
  109. 1, 36, :_reduce_26,
  110. 1, 36, :_reduce_27,
  111. 1, 36, :_reduce_28,
  112. 1, 36, :_reduce_29,
  113. 2, 35, :_reduce_30,
  114. 2, 35, :_reduce_31,
  115. 1, 35, :_reduce_none,
  116. 3, 34, :_reduce_33,
  117. 1, 34, :_reduce_34 ]
  118. 1 racc_reduce_n = 35
  119. 1 racc_shift_n = 60
  120. 1 racc_token_table = {
  121. false => 0,
  122. :error => 1,
  123. :NUMBER => 2,
  124. :R => 3,
  125. :U => 4,
  126. :C => 5,
  127. :F => 6,
  128. :S => 7,
  129. :PLUS => 8,
  130. :MINUS => 9,
  131. :ASTERISK => 10,
  132. :SLASH => 11,
  133. :PARENL => 12,
  134. :PARENR => 13,
  135. :BRACKETL => 14,
  136. :BRACKETR => 15,
  137. :LESS => 16,
  138. :GREATER => 17,
  139. :EQUAL => 18,
  140. :NOT => 19,
  141. :AT => 20,
  142. :CMP_OP => 21 }
  143. 1 racc_nt_base = 22
  144. 1 racc_use_result_var = true
  145. Racc_arg = [
  146. 1 racc_action_table,
  147. racc_action_check,
  148. racc_action_default,
  149. racc_action_pointer,
  150. racc_goto_table,
  151. racc_goto_check,
  152. racc_goto_default,
  153. racc_goto_pointer,
  154. racc_nt_base,
  155. racc_reduce_table,
  156. racc_token_table,
  157. racc_shift_n,
  158. racc_reduce_n,
  159. racc_use_result_var ]
  160. 1 then: 1 else: 0 Ractor.make_shareable(Racc_arg) if defined?(Ractor)
  161. 1 Racc_token_to_s_table = [
  162. "$end",
  163. "error",
  164. "NUMBER",
  165. "R",
  166. "U",
  167. "C",
  168. "F",
  169. "S",
  170. "PLUS",
  171. "MINUS",
  172. "ASTERISK",
  173. "SLASH",
  174. "PARENL",
  175. "PARENR",
  176. "BRACKETL",
  177. "BRACKETR",
  178. "LESS",
  179. "GREATER",
  180. "EQUAL",
  181. "NOT",
  182. "AT",
  183. "CMP_OP",
  184. "$start",
  185. "expr",
  186. "secret",
  187. "notations",
  188. "modifier",
  189. "target",
  190. "bracket",
  191. "at",
  192. "modifier_expr",
  193. "mul",
  194. "add",
  195. "dice",
  196. "term",
  197. "unary",
  198. "round_type" ]
  199. 1 then: 1 else: 0 Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
  200. 1 Racc_debug_parser = false
  201. ##### State transition tables end #####
  202. # reduce 0 omitted
  203. 1 def _reduce_1(val, _values, result)
  204. 32 result = UpperDice::Node::Command.new(
  205. secret: val[0],
  206. notations: val[1],
  207. modifier: val[2],
  208. cmp_op: val[3][:cmp_op],
  209. target_number: val[3][:target]
  210. )
  211. 32 result
  212. end
  213. 1 def _reduce_2(val, _values, result)
  214. 13 result = UpperDice::Node::Command.new(
  215. secret: val[0],
  216. notations: val[1],
  217. modifier: val[3],
  218. cmp_op: val[4][:cmp_op],
  219. target_number: val[4][:target],
  220. reroll_threshold: val[2]
  221. )
  222. 13 result
  223. end
  224. 1 def _reduce_3(val, _values, result)
  225. 3 result = UpperDice::Node::Command.new(
  226. secret: val[0],
  227. notations: val[1],
  228. modifier: val[2],
  229. cmp_op: val[3][:cmp_op],
  230. target_number: val[3][:target],
  231. reroll_threshold: val[4]
  232. )
  233. 3 result
  234. end
  235. 1 def _reduce_4(val, _values, result)
  236. 252 result = false
  237. 252 result
  238. end
  239. 1 def _reduce_5(val, _values, result)
  240. 9 result = true
  241. 9 result
  242. end
  243. 1 def _reduce_6(val, _values, result)
  244. 37 result = Arithmetic::Node::Number.new(0)
  245. 37 result
  246. end
  247. 1 def _reduce_7(val, _values, result)
  248. 11 result = val[0]
  249. 11 result
  250. end
  251. 1 def _reduce_8(val, _values, result)
  252. 10 result = val[1]
  253. 10 result
  254. end
  255. 1 def _reduce_9(val, _values, result)
  256. 1 result = Arithmetic::Node::Negative.new(val[1])
  257. 1 result
  258. end
  259. 1 def _reduce_10(val, _values, result)
  260. 4 result = Arithmetic::Node::BinaryOp.new(val[0], :+, val[2])
  261. 4 result
  262. end
  263. 1 def _reduce_11(val, _values, result)
  264. 1 result = Arithmetic::Node::BinaryOp.new(val[0], :-, val[2])
  265. 1 result
  266. end
  267. 1 def _reduce_12(val, _values, result)
  268. 6 result = {}
  269. 6 result
  270. end
  271. 1 def _reduce_13(val, _values, result)
  272. 42 cmp_op, target = val
  273. 42 else: 42 then: 0 raise ParseError unless cmp_op
  274. 42 result = {cmp_op: cmp_op, target: target}
  275. 42 result
  276. end
  277. 1 def _reduce_14(val, _values, result)
  278. 13 result = val[1]
  279. 13 result
  280. end
  281. 1 def _reduce_15(val, _values, result)
  282. 3 result = val[1]
  283. 3 result
  284. end
  285. 1 def _reduce_16(val, _values, result)
  286. 6 notations = val[0]
  287. 6 notations.push(val[2])
  288. 6 result = notations
  289. 6 result
  290. end
  291. 1 def _reduce_17(val, _values, result)
  292. 48 result = [val[0]]
  293. 48 result
  294. end
  295. 1 def _reduce_18(val, _values, result)
  296. 54 times = val[0]
  297. 54 sides = val[2]
  298. 54 result = UpperDice::Node::Notation.new(times, sides)
  299. 54 result
  300. end
  301. 1 def _reduce_19(val, _values, result)
  302. 3 result = Arithmetic::Node::BinaryOp.new(val[0], :+, val[2])
  303. 3 result
  304. end
  305. 1 def _reduce_20(val, _values, result)
  306. 2 result = Arithmetic::Node::BinaryOp.new(val[0], :-, val[2])
  307. 2 result
  308. end
  309. # reduce 21 omitted
  310. 1 def _reduce_22(val, _values, result)
  311. result = Arithmetic::Node::BinaryOp.new(val[0], :*, val[2])
  312. result
  313. end
  314. 1 def _reduce_23(val, _values, result)
  315. 2 divied_class = val[3]
  316. 2 result = divied_class.new(val[0], val[2])
  317. 2 result
  318. end
  319. # reduce 24 omitted
  320. 1 def _reduce_25(val, _values, result)
  321. 2 result = Arithmetic::Node::DivideWithGameSystemDefault
  322. 2 result
  323. end
  324. 1 def _reduce_26(val, _values, result)
  325. result = Arithmetic::Node::DivideWithCeil
  326. result
  327. end
  328. 1 def _reduce_27(val, _values, result)
  329. result = Arithmetic::Node::DivideWithCeil
  330. result
  331. end
  332. 1 def _reduce_28(val, _values, result)
  333. result = Arithmetic::Node::DivideWithRound
  334. result
  335. end
  336. 1 def _reduce_29(val, _values, result)
  337. result = Arithmetic::Node::DivideWithFloor
  338. result
  339. end
  340. 1 def _reduce_30(val, _values, result)
  341. result = val[1]
  342. result
  343. end
  344. 1 def _reduce_31(val, _values, result)
  345. result = Arithmetic::Node::Negative.new(val[1])
  346. result
  347. end
  348. # reduce 32 omitted
  349. 1 def _reduce_33(val, _values, result)
  350. 2 result = val[1]
  351. 2 result
  352. end
  353. 1 def _reduce_34(val, _values, result)
  354. 246 result = Arithmetic::Node::Number.new(val[0])
  355. 246 result
  356. end
  357. 1 def _reduce_none(val, _values, result)
  358. val[0]
  359. end
  360. end # class Parser
  361. end # module UpperDice
  362. end # module CommonCommand
  363. end # module BCDice

lib/bcdice/common_command/version.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module CommonCommand
  4. 1 module Version
  5. 1 PREFIX_PATTERN = /BCDiceVersion/.freeze
  6. 1 class << self
  7. 1 def eval(command, _game_system, _randomizer)
  8. 214 command = command.split(" ", 2).first
  9. 214 then: 1 else: 213 if command.match?(/^BCDiceVersion$/i)
  10. 1 Result.new.tap do |r|
  11. 1 r.text = "BCDice #{BCDice::VERSION}"
  12. end
  13. end
  14. end
  15. end
  16. end
  17. end
  18. end

lib/bcdice/deprecated/checker.rb

100.0% lines covered

90.91% branches covered

23 relevant lines. 23 lines covered and 0 lines missed.
11 total branches, 10 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module Deprecated
  4. # 2D6などの特定の加算ダイスの結果をゲームシステムごとにカスタマイズするための
  5. # @deprecated Base#result_2d6 等を利用してください
  6. 1 module Checker
  7. 1 private
  8. # @param total [Integer] コマンド合計値
  9. # @param rand_results [Array<CommonCommand::AddDice::Randomizer::RandResult>] ダイスの一覧
  10. # @param cmp_op [Symbol] 比較演算子
  11. # @param target [Integer, String] 目標値の整数か'?'
  12. # @return [Result, nil]
  13. 1 def check_result_legacy(total, rand_results, cmp_op, target)
  14. 811 sides_list = rand_results.map(&:sides)
  15. 811 value_list = rand_results.map(&:value)
  16. 811 dice_total = value_list.sum()
  17. ret =
  18. 811 else: 165 case sides_list
  19. when: 268 when [100]
  20. 268 check_1D100(total, dice_total, cmp_op, target)
  21. when: 62 when [20]
  22. 62 check_1D20(total, dice_total, cmp_op, target)
  23. when: 316 when [6, 6]
  24. 316 check_2D6(total, dice_total, value_list, cmp_op, target)
  25. end
  26. 811 else: 798 then: 13 return Result.new(ret.delete_prefix(" > ")) unless ret.nil? || ret.empty?
  27. ret =
  28. 798 else: 333 case sides_list.uniq
  29. when: 52 when [10]
  30. 52 check_nD10(total, dice_total, value_list, cmp_op, target)
  31. when: 413 when [6]
  32. 413 check_nD6(total, dice_total, value_list, cmp_op, target)
  33. end
  34. 798 else: 798 then: 0 return Result.new(ret.delete_prefix(" > ")) unless ret.nil? || ret.empty?
  35. 798 return nil
  36. end
  37. # @param total [Integer]
  38. # @param dice_total [Integer]
  39. # @param cmp_op [Symbol]
  40. # @param target
  41. # @return [String, nil]
  42. # @deprecated Base#result_1d100 を使ってください
  43. 1 def check_1D100(total, dice_total, cmp_op, target); end
  44. # @param (see #check_1D100)
  45. # @return [String, nil]
  46. # @deprecated Base#result_1d20 を使ってください
  47. 1 def check_1D20(total, dice_total, cmp_op, target); end
  48. # @param total [Integer]
  49. # @param dice_total [Integer]
  50. # @param dice_list [Array<Integer>]
  51. # @param cmp_op [Symbol]
  52. # @param target
  53. # @return [String, nil]
  54. # @deprecated Base#result_nd10 を使ってください
  55. 1 def check_nD10(total, dice_total, dice_list, cmp_op, target); end
  56. # @param (see #check_nD10)
  57. # @return [String, nil]
  58. # @deprecated Base#result_2d6 を使ってください
  59. 1 def check_2D6(total, dice_total, dice_list, cmp_op, target); end
  60. # @param (see #check_nD10)
  61. # @return [String, nil]
  62. # @deprecated Base#result_nd6 を使ってください
  63. 1 def check_nD6(total, dice_total, dice_list, cmp_op, target); end
  64. end
  65. end
  66. end

lib/bcdice/dice_table.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/dice_table/roll_result"
  3. 1 require "bcdice/dice_table/chain_table"
  4. 1 require "bcdice/dice_table/d66_grid_table"
  5. 1 require "bcdice/dice_table/d66_half_grid_table"
  6. 1 require "bcdice/dice_table/d66_one_third_table"
  7. 1 require "bcdice/dice_table/d66_left_range_table"
  8. 1 require "bcdice/dice_table/d66_parity_table"
  9. 1 require "bcdice/dice_table/d66_range_table"
  10. 1 require "bcdice/dice_table/d66_table"
  11. 1 require "bcdice/dice_table/range_table"
  12. 1 require "bcdice/dice_table/sai_fic_skill_table"
  13. 1 require "bcdice/dice_table/table"

lib/bcdice/dice_table/chain_table.rb

94.12% lines covered

75.0% branches covered

17 relevant lines. 16 lines covered and 1 lines missed.
4 total branches, 3 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module DiceTable
  4. 1 class ChainTable
  5. # @param [String] name 表の名前
  6. # @param [String] type 項目を選ぶときのダイスロールの方法 '1D6'など
  7. # @param [Array<String, #roll>] items 表の項目の配列
  8. 1 def initialize(name, type, items)
  9. 34 @name = name
  10. 34 @items = items.freeze
  11. 34 m = /(\d+)D(\d+)/i.match(type)
  12. 34 else: 34 then: 0 unless m
  13. raise ArgumentError, "Unexpected table type: #{type}"
  14. end
  15. 34 @times = m[1].to_i
  16. 34 @sides = m[2].to_i
  17. end
  18. # 表を振る
  19. # @param randomizer [#roll_sum] ランダマイザ
  20. # @return [String] 結果
  21. 1 def roll(randomizer)
  22. 86 value = randomizer.roll_sum(@times, @sides)
  23. 86 index = value - @times
  24. 86 chosen = @items[index]
  25. 86 then: 78 else: 8 chosen = chosen.roll(randomizer) if chosen.respond_to?(:roll)
  26. 86 return RollResult.new(@name, value, chosen)
  27. end
  28. end
  29. end
  30. end

lib/bcdice/dice_table/d66_grid_table.rb

100.0% lines covered

100.0% branches covered

16 relevant lines. 16 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module DiceTable
  4. # D66を振って6x6マスの表を参照する
  5. 1 class D66GridTable
  6. # @param key [String]
  7. # @param locale [Symbol]
  8. # @return [D66GridTable]
  9. 1 def self.from_i18n(key, locale)
  10. 16 table = I18n.t(key, locale: locale, raise: true)
  11. 16 new(table[:name], table[:items])
  12. end
  13. # @param [String] name 表の名前
  14. # @param [Array<Array<String>>] items 表の項目の配列
  15. 1 def initialize(name, items)
  16. 26 @name = name
  17. 26 @items = items.freeze
  18. end
  19. # 表を振る
  20. # @param randomizer [#roll_once] ランダマイザ
  21. # @return [String] 結果
  22. 1 def roll(randomizer)
  23. 209 dice1 = randomizer.roll_once(6)
  24. 209 dice2 = randomizer.roll_once(6)
  25. 209 value = dice1 * 10 + dice2
  26. 209 index1 = dice1 - 1
  27. 209 index2 = dice2 - 1
  28. 209 return RollResult.new(@name, value, @items[index1][index2])
  29. end
  30. end
  31. end
  32. end

lib/bcdice/dice_table/d66_half_grid_table.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/dice_table/d66_grid_table"
  3. 1 module BCDice
  4. 1 module DiceTable
  5. # D66を振って6x6マスの表を参照する
  6. 1 class D66HalfGridTable < D66GridTable
  7. # @param key [String]
  8. # @param locale [Symbol]
  9. # @return [D66HalfGridTable]
  10. 1 def self.from_i18n(key, locale)
  11. 26 table = I18n.t(key, locale: locale, raise: true)
  12. 26 new(table[:name], table[:items_1_2_3], table[:items_4_5_6])
  13. end
  14. # @param [String] name 表の名前
  15. # @param [Array<String>] items_1_2_3
  16. # @param [Array<String>] items_4_5_6
  17. 1 def initialize(name, items_1_2_3, items_4_5_6)
  18. 32 @name = name
  19. @items = [
  20. 32 items_1_2_3,
  21. items_1_2_3,
  22. items_1_2_3,
  23. items_4_5_6,
  24. items_4_5_6,
  25. items_4_5_6,
  26. ].freeze
  27. end
  28. end
  29. end
  30. end

lib/bcdice/dice_table/d66_left_range_table.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/dice_table/d66_table"
  3. 1 module BCDice
  4. 1 module DiceTable
  5. # 左側(十の位)のみ Range を用いる D66 表
  6. 1 class D66LeftRangeTable < D66Table
  7. # @param name [String] 表の名前
  8. # @param sort_type [Symbol] 出目入れ替えの方式 BCDice::D66SortType
  9. # @param items [Array<(Range, Array<String>)>] 表の項目の配列
  10. 1 def initialize(name, sort_type, items)
  11. 11 expanded_items = {}
  12. 11 items.each do |item|
  13. 40 range, right_items = item
  14. 40 range.each do |left_value|
  15. 66 right_items.each_with_index do |right_item, right_value|
  16. 396 key = left_value * 10 + (right_value + 1)
  17. 396 expanded_items[key] = right_item
  18. end
  19. end
  20. end
  21. 11 super(name, sort_type, expanded_items)
  22. end
  23. end
  24. end
  25. end

lib/bcdice/dice_table/d66_one_third_table.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/dice_table/d66_grid_table"
  3. 1 module BCDice
  4. 1 module DiceTable
  5. # D66を振って6x6マスの表を参照する
  6. 1 class D66OneThirdTable < D66GridTable
  7. # @param key [String]
  8. # @param locale [Symbol]
  9. # @return [D66OneThirdTable]
  10. 1 def self.from_i18n(key, locale)
  11. 10 table = I18n.t(key, locale: locale, raise: true)
  12. 10 new(table[:name], table[:items_1_2], table[:items_3_4], table[:items_5_6])
  13. end
  14. # @param [String] name 表の名前
  15. # @param [Array<String>] items_1_2
  16. # @param [Array<String>] items_3_4
  17. # @param [Array<String>] items_5_6
  18. 1 def initialize(name, items_1_2, items_3_4, items_5_6)
  19. 13 @name = name
  20. @items = [
  21. 13 items_1_2,
  22. items_1_2,
  23. items_3_4,
  24. items_3_4,
  25. items_5_6,
  26. items_5_6,
  27. ].freeze
  28. end
  29. end
  30. end
  31. end

lib/bcdice/dice_table/d66_parity_table.rb

100.0% lines covered

100.0% branches covered

19 relevant lines. 19 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module DiceTable
  4. # 出目の偶奇による場合分け機能をもつD66表
  5. 1 class D66ParityTable
  6. # @param key [String]
  7. # @param locale [Symbol]
  8. # @return [D66ParityTable]
  9. 1 def self.from_i18n(key, locale)
  10. 4 table = I18n.t(key, locale: locale, raise: true)
  11. 4 new(table[:name], table[:odd], table[:even])
  12. end
  13. # @param name [String] 表の名前
  14. # @param odd [Array<String>] 左ダイスが奇数だったときの次層テーブル(サイズ6)
  15. # @param even [Array<String>] 左ダイスが偶数だったときの次層テーブル(サイズ6)
  16. 1 def initialize(name, odd, even)
  17. 10 @name = name
  18. 10 @odd = odd.freeze
  19. 10 @even = even.freeze
  20. end
  21. # 表を振る
  22. # @param randomizer [#roll_once] ランダマイザ
  23. # @return [String] 結果
  24. 1 def roll(randomizer)
  25. 41 dice1 = randomizer.roll_once(6)
  26. 41 dice2 = randomizer.roll_once(6)
  27. 41 then: 21 if dice1.odd?
  28. 21 second_table = @odd
  29. else: 20 else
  30. 20 second_table = @even
  31. end
  32. 41 result = second_table[dice2 - 1]
  33. 41 key = dice1 * 10 + dice2
  34. 41 return RollResult.new(@name, key, result)
  35. end
  36. end
  37. end
  38. end

lib/bcdice/dice_table/d66_range_table.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module DiceTable
  4. # 項目をRangeを用いて参照するD66表
  5. 1 class D66RangeTable
  6. # @param name [String] 表の名前
  7. # @param items [Array<(Range, String)>] 表の項目の配列
  8. 1 def initialize(name, items)
  9. 55 @name = name
  10. 55 @items = items.freeze
  11. end
  12. # 表を振る
  13. # @param randomizer [#roll_once] ランダマイザ
  14. # @return [String] 結果
  15. 1 def roll(randomizer)
  16. 95 dice1 = randomizer.roll_once(6)
  17. 95 dice2 = randomizer.roll_once(6)
  18. 95 key = dice1 * 10 + dice2
  19. 706 chosen = @items.find { |row| row[0].include?(key) }
  20. 95 return RollResult.new(@name, key, chosen[1])
  21. end
  22. end
  23. end
  24. end

lib/bcdice/dice_table/d66_table.rb

100.0% lines covered

100.0% branches covered

22 relevant lines. 22 lines covered and 0 lines missed.
5 total branches, 5 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module DiceTable
  4. # D66を振って出目を昇順/降順にして表を参照する
  5. 1 class D66Table
  6. # @param key [String]
  7. # @param locale [Symbol]
  8. # @return [D66Table]
  9. 1 def self.from_i18n(key, locale)
  10. 200 table = I18n.t(key, locale: locale)
  11. 200 sort_type = D66SortType.const_get(table[:d66_sort_type])
  12. 200 new(table[:name], sort_type, table[:items])
  13. end
  14. # @param [String] name 表の名前
  15. # @param [Symbol] sort_type 出目入れ替えの方式 BCDice::D66SortType
  16. # @param [Hash] items 表の項目 Key は数値
  17. 1 def initialize(name, sort_type, items)
  18. 347 @name = name
  19. 347 @sort_type = sort_type
  20. 347 @items = items.freeze
  21. end
  22. # 表を振る
  23. # @param randomizer [#roll_barabara] ランダマイザ
  24. # @return [String] 結果
  25. 1 def roll(randomizer)
  26. 593 dice = randomizer.roll_barabara(2, 6)
  27. 593 else: 129 case @sort_type
  28. when: 460 when D66SortType::ASC
  29. 460 dice.sort!
  30. when: 4 when D66SortType::DESC
  31. 4 dice.sort!.reverse!
  32. end
  33. 593 key = dice[0] * 10 + dice[1]
  34. 593 chosen = @items[key]
  35. 593 then: 11 else: 582 chosen = chosen.roll(randomizer) if chosen.respond_to?(:roll)
  36. 593 RollResult.new(@name, key, chosen)
  37. end
  38. 1 def choice(key)
  39. 2 RollResult.new(@name, key, @items[key])
  40. end
  41. end
  42. end
  43. end

lib/bcdice/dice_table/range_table.rb

96.34% lines covered

81.82% branches covered

82 relevant lines. 79 lines covered and 3 lines missed.
22 total branches, 18 branches covered and 4 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module DiceTable
  4. # 各項目について、Rangeを用いて出目の合計の範囲を指定する、表のクラス。
  5. #
  6. # このクラスを使うと、表の定義を短く書ける。
  7. # このクラスを使って表を定義するときは、各項目を以下の形で書く。
  8. #
  9. # [出目の合計の範囲, 内容]
  10. #
  11. # 「出目の合計の範囲」には、Integerを要素とするRangeか、Integerを置ける。
  12. #
  13. # roll メソッドで表を振ると、出目の合計値と対応する項目が選ばれる。
  14. #
  15. # @example 表の定義(バトルテックの致命的命中表)
  16. # CRITICAL_TABLE = RangeTable.new(
  17. # '致命的命中表',
  18. # '2D6',
  19. # [
  20. # [2..7, '致命的命中はなかった'],
  21. # [8..9, '1箇所の致命的命中'],
  22. # [10..11, '2箇所の致命的命中'],
  23. # [12, 'その部位が吹き飛ぶ(腕、脚、頭)または3箇所の致命的命中(胴)']
  24. # ]
  25. # )
  26. #
  27. # @example 表を振った結果
  28. # CRITICAL_TABLE.roll(bcdice).formatted
  29. # # 出目の合計が7の場合 :"致命的命中表(7) > 致命的命中はなかった"
  30. # # 出目の合計が8の場合 :"致命的命中表(8) > 1箇所の致命的命中"
  31. # # 出目の合計が9の場合 :"致命的命中表(9) > 1箇所の致命的命中"
  32. # # 出目の合計が10の場合:"致命的命中表(10) > 2箇所の致命的命中"
  33. 1 class RangeTable
  34. # 表を振った結果を表す構造体
  35. # @!attribute [rw] sum
  36. # @return [Integer] 出目の合計
  37. # @!attribute [rw] values
  38. # @return [Array<Integer>] 出目の配列
  39. # @!attribute [rw] content
  40. # @return [Object] 選ばれた項目の内容
  41. # @!attribute [rw] formatted
  42. # @return [String] 整形された結果
  43. 1 RollResult = Struct.new(:sum, :values, :content, :formatted) do
  44. 1 alias_method :to_s, :formatted
  45. end
  46. # 表の項目を表す構造体
  47. # @!attribute [rw] range
  48. # @return [Range] 出目の合計の範囲
  49. # @!attribute [rw] content
  50. # @return [Object] 内容
  51. 1 Item = Struct.new(:range, :content)
  52. # 項目を選ぶときのダイスロールの方法を表す正規表現
  53. 1 DICE_ROLL_METHOD_RE = /\A(\d+)D(\d+)\z/i.freeze
  54. # 表を振った結果の整形処理(既定の処理)
  55. 1 DEFAULT_FORMATTER = lambda do |table, result|
  56. 342 "#{table.name}(#{result.sum}) > #{result.content}"
  57. end
  58. # @return [String] 表の名前
  59. 1 attr_reader :name
  60. # @return [Integer] 振るダイスの個数
  61. 1 attr_reader :num_of_dice
  62. # @return [Integer] 振るダイスの面数
  63. 1 attr_reader :num_of_sides
  64. 1 class << self
  65. 1 def from_i18n(key, locale)
  66. 20 table = I18n.t(key, locale: locale)
  67. 20 converted_items = table[:items].map do |item|
  68. 366 [conv_string_range(item[0]), item[1]]
  69. end
  70. 20 new(table[:name], table[:type], converted_items)
  71. end
  72. 1 def conv_string_range(x)
  73. 372 else: 1 case x
  74. when: 1 when Integer
  75. 1 return x
  76. when: 370 when String
  77. 1066 then: 348 else: 22 return x.include?("..") ? Range.new(*x.split("..", 2).map { |n| Integer(n) }) : Integer(x)
  78. end
  79. 1 raise(
  80. TypeError,
  81. "#{@name}: #{x} (#{x.class}) must be a String or an Integer"
  82. )
  83. end
  84. end
  85. # 表を初期化する
  86. #
  87. # ブロックを与えると、独自の結果整形処理を指定できる。
  88. # ブロックは振った表(+table+)と振った結果(+result+)を引数として受け取る。
  89. #
  90. # @param [String] name 表の名前
  91. # @param [String] dice_roll_method
  92. # 項目を選ぶときのダイスロールの方法(+'1D6'+ など)
  93. # @param [Array<(Range, Object)>, Array<(Integer, Object)>] items
  94. # 表の項目の配列。[出目の合計の範囲, 内容]
  95. # @yieldparam [RangeTable] table 振った表
  96. # @yieldparam [RollResult] result 表を振った結果
  97. # @raise [ArgumentError] ダイスロール方法が正しい書式で指定されていなかった場合
  98. # @raise [TypeError] 範囲の型が正しくなかった場合
  99. # @raise [RangeError] 出目の合計の最小値がカバーされていなかった場合
  100. # @raise [RangeError] 出目の合計の最大値がカバーされていなかった場合
  101. # @raise [RangeError] 出目の合計の範囲にずれや重なりがあった場合
  102. #
  103. # @example 表の定義(バトルテックの致命的命中表)
  104. # CRITICAL_TABLE = RangeTable.new(
  105. # '致命的命中表',
  106. # '2D6',
  107. # [
  108. # [2..7, '致命的命中はなかった'],
  109. # [8..9, '1箇所の致命的命中'],
  110. # [10..11, '2箇所の致命的命中'],
  111. # [12, 'その部位が吹き飛ぶ(腕、脚、頭)または3箇所の致命的命中(胴)']
  112. # ]
  113. # )
  114. #
  115. # @example 独自の結果整形処理を指定する場合
  116. # CRITICAL_TABLE_WITH_FORMATTER = RangeTable.new(
  117. # '致命的命中表',
  118. # '2D6',
  119. # [
  120. # [2..7, '致命的命中はなかった'],
  121. # [8..9, '1箇所の致命的命中'],
  122. # [10..11, '2箇所の致命的命中'],
  123. # [12, 'その部位が吹き飛ぶ(腕、脚、頭)または3箇所の致命的命中(胴)']
  124. # ]
  125. # ) do |table, result|
  126. # "致命的命中発生? > #{result.sum}[#{result.values}] > #{result.content}"
  127. # end
  128. #
  129. # CRITICAL_TABLE_WITH_FORMATTER.roll(bcdice).formatted
  130. # #=> "致命的命中発生? > 11[5,6] > 2箇所の致命的命中"
  131. 1 def initialize(name, dice_roll_method, items, &formatter)
  132. 129 @name = name.freeze
  133. 129 @formatter = formatter || DEFAULT_FORMATTER
  134. 129 m = DICE_ROLL_METHOD_RE.match(dice_roll_method)
  135. 129 else: 127 then: 2 unless m
  136. 2 raise(
  137. ArgumentError,
  138. "#{@name}: invalid dice roll method: #{dice_roll_method}"
  139. )
  140. end
  141. 127 @num_of_dice = m[1].to_i
  142. 127 @num_of_sides = m[2].to_i
  143. 127 store(items)
  144. end
  145. # 指定された値に対応する項目を返す
  146. # @param [Integer] value 値(出目の合計)
  147. # @return [Item] 指定された値に対応する項目
  148. # @raise [RangeError] 範囲外の値が指定された場合
  149. 1 def fetch(value)
  150. 2612 item = @items.find { |i| i.range.include?(value) }
  151. 363 else: 363 then: 0 unless item
  152. raise RangeError, "#{@name}: value is out of range: #{value}"
  153. end
  154. 363 return item
  155. end
  156. # 表を振る
  157. # @param randomizer [#roll_barabara] ランダマイザ
  158. # @return [RollResult] 表を振った結果
  159. 1 def roll(randomizer)
  160. 351 values = randomizer.roll_barabara(@num_of_dice, @num_of_sides)
  161. 351 sum = values.sum()
  162. 351 result = RollResult.new(sum, values, fetch(sum).content)
  163. 351 result.formatted = @formatter[self, result]
  164. 351 return result
  165. end
  166. 1 private
  167. # 表の項目を格納する
  168. # @param [Array<(Range, Object)>, Array<(Integer, Object)>] items
  169. # 表の項目の配列。[出目の合計の範囲, 内容]
  170. # @return [self]
  171. # @raise [TypeError] 範囲の型が正しくなかった場合
  172. # @raise [RangeError] 出目の合計の最小値がカバーされていなかった場合
  173. # @raise [RangeError] 出目の合計の最大値がカバーされていなかった場合
  174. # @raise [RangeError] 出目の合計の範囲にずれや重なりがあった場合
  175. 1 def store(items)
  176. 1371 items_with_range = items.map { |r, c| [coerce_to_int_range(r), c] }
  177. 1369 sorted_items = items_with_range.sort_by { |r, _| r.min }
  178. 126 assert_min_sum_is_covered(sorted_items)
  179. 126 assert_max_sum_is_covered(sorted_items)
  180. 126 assert_no_gap_or_overlap_in_ranges(sorted_items)
  181. 123 @items = sorted_items
  182. 1237 .map { |range, content| Item.new(range, content.freeze).freeze }
  183. .freeze
  184. 123 self
  185. end
  186. # 引数を強制的に整数を要素とするRangeに変換する
  187. # @param [Range, Integer] x 変換対象
  188. # @return [Range] 整数を要素とするRange
  189. # @raise [TypeError] xの型に対応していなかった場合
  190. 1 def coerce_to_int_range(x)
  191. 1244 else: 0 case x
  192. when: 370 when Integer
  193. 370 return Range.new(x, x)
  194. when: 874 when Range
  195. 874 then: 873 else: 1 if x.begin.is_a?(Integer) && x.end.is_a?(Integer)
  196. 873 return x
  197. end
  198. end
  199. 1 raise(
  200. TypeError,
  201. "#{@name}: #{x} (#{x.class}) must be an Integer or a Range with Integers "
  202. )
  203. end
  204. # 出目の合計の最小値がカバーされていることを確認する
  205. # @param [Array<(Range, Object)>] sorted_items
  206. # ソートされた、項目の配列
  207. # @return [self]
  208. # @raise [RangeError] 出目の合計の最小値がカバーされていなかった場合
  209. 1 def assert_min_sum_is_covered(sorted_items)
  210. 126 min_sum = @num_of_dice
  211. 126 range = sorted_items.first[0]
  212. 126 else: 126 then: 0 unless range.include?(min_sum)
  213. raise(
  214. RangeError,
  215. "#{@name}: min value (#{min_sum}) is not covered: #{range}"
  216. )
  217. end
  218. 126 self
  219. end
  220. # 出目の合計の最大値がカバーされていることを確認する
  221. # @param [Array<(Range, Object)>] sorted_items
  222. # ソートされた、項目の配列
  223. # @return [self]
  224. # @raise [RangeError] 出目の合計の最大値がカバーされていなかった場合
  225. 1 def assert_max_sum_is_covered(sorted_items)
  226. 126 max_sum = @num_of_dice * @num_of_sides
  227. 126 range = sorted_items.last[0]
  228. 126 else: 126 then: 0 unless range.include?(max_sum)
  229. raise(
  230. RangeError,
  231. "#{@name}: max value (#{max_sum}) is not covered: #{range}"
  232. )
  233. end
  234. 126 self
  235. end
  236. # 出目の合計の範囲にずれや重なりがないことを確認する
  237. # @param [Array<(Range, Object)>] sorted_items
  238. # ソートされた、項目の配列
  239. # @return [self]
  240. # @raise [RangeError] 出目の合計の範囲にずれや重なりがあった場合
  241. 1 def assert_no_gap_or_overlap_in_ranges(sorted_items)
  242. 126 sorted_items.each_cons(2) do |i1, i2|
  243. 1117 r1 = i1[0]
  244. 1117 r2 = i2[0]
  245. 1117 max1 = r1.max
  246. 1117 next_of_max1 = max1 + 1
  247. 1117 then: 1 else: 1116 if r2.include?(max1)
  248. 1 raise RangeError, "#{@name}: Range overlap: #{r1} and #{r2}"
  249. end
  250. 1116 else: 1114 then: 2 unless r2.include?(next_of_max1)
  251. 2 raise RangeError, "#{@name}: Range gap: #{r1} and #{r2}"
  252. end
  253. end
  254. 123 self
  255. end
  256. end
  257. end
  258. end

lib/bcdice/dice_table/roll_result.rb

100.0% lines covered

100.0% branches covered

18 relevant lines. 18 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module DiceTable
  4. 1 class RollResult
  5. # @param table_name [String]
  6. # @param value [Integer]
  7. # @param body [String, RollResult]
  8. 1 def initialize(table_name, value, body)
  9. 4272 @table_name = table_name
  10. 4272 @value = value
  11. 4272 @body = body
  12. end
  13. # @return [String]
  14. 1 attr_reader :table_name
  15. # @return [Integer]
  16. 1 attr_reader :value
  17. # @return [String, RollResult]
  18. 1 attr_reader :body
  19. # @return [String]
  20. 1 def to_s
  21. 3650 "#{@table_name}(#{@value}) > #{@body}"
  22. end
  23. # @return [String]
  24. 1 def last_body
  25. 18 then: 4 if @body.is_a?(RollResult)
  26. 4 @body.last_body
  27. else: 14 else
  28. 14 @body
  29. end
  30. end
  31. # 一部のゲームシステムが String#empty? を想定してチェックしているため
  32. # @return [false]
  33. 1 def empty?
  34. 313 false
  35. end
  36. end
  37. end
  38. end

lib/bcdice/dice_table/sai_fic_skill_table.rb

100.0% lines covered

100.0% branches covered

44 relevant lines. 44 lines covered and 0 lines missed.
6 total branches, 6 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/dice_table/sai_fic_skill_table/category"
  3. 1 require "bcdice/dice_table/sai_fic_skill_table/skill"
  4. 1 module BCDice
  5. 1 module DiceTable
  6. 1 class SaiFicSkillTable
  7. # @param key [String]
  8. # @param locale [Symbol]
  9. # @param rtt [String] RTTに相当するコマンド
  10. # @param rct [String] RCTに相当するコマンド
  11. # @param rttn [Array] RTT1~6に相当するコマンドの配列
  12. # @return [SaiFicSkillTable]
  13. 1 def self.from_i18n(key, locale, rtt: nil, rct: nil, rttn: nil)
  14. 13 global = I18n.t("RTT", locale: locale, raise: false, default: {})
  15. 13 table = global.merge(I18n.t(key, locale: locale, raise: true))
  16. 13 items = table[:items]
  17. 50 table = table.select { |k, _| [:rtt_format, :rttn_format, :rct_format, :s_format].include?(k) }
  18. 13 new(items, **table, rtt: rtt, rct: rct, rttn: rttn)
  19. end
  20. 1 DEFAULT_RTT = "ランダム特技表(%<category_dice>d,%<row_dice>d) > %<text>s"
  21. 1 DEFAULT_RCT = "ランダム分野表(%<category_dice>d) > %<category_name>s"
  22. 1 DEFAULT_RTTN = "%<category_name>s分野ランダム特技表(%<row_dice>d) > %<text>s"
  23. 1 DEFAULT_S = "《%<skill_name>s/%<category_name>s%<row_dice>d》"
  24. # サイコロ・フィクション用ダイステーブルを初期化する。
  25. # 既存の実装の互換性維持とルールブックの記載に準拠するために、コマンドと書式文字列を指定できる。
  26. # @param items [Array] 特技リスト
  27. # @param rtt [String] RTTに相当するコマンド
  28. # @param rct [String] RCTに相当するコマンド
  29. # @param rttn [Array] RTT1~6に相当するコマンドの配列
  30. # @param rtt_format [String] RTTコマンドの出力用の書式文字列
  31. # @param rct_format [String] RCTコマンドの出力用の書式文字列
  32. # @param rttn_format [String] RTTNコマンドの出力用の書式文字列
  33. # @param s_format [String] Skill#to_s出力用の書式文字列
  34. 1 def initialize(items, rtt: nil, rct: nil, rttn: nil, rtt_format: DEFAULT_RTT, rct_format: DEFAULT_RCT, rttn_format: DEFAULT_RTTN, s_format: DEFAULT_S)
  35. 24 @categories = items.map.with_index(1) do |(name, skills), index|
  36. 138 SaiFicSkillTable::Category.new(name, skills, index, s_format)
  37. end
  38. 24 @rtt = rtt
  39. 24 @rct = rct
  40. 24 @rttn = rttn.to_a
  41. 24 @rtt_format = rtt_format
  42. 24 @rct_format = rct_format
  43. 24 @rttn_format = rttn_format
  44. end
  45. 1 RTTN = ["RTT1", "RTT2", "RTT3", "RTT4", "RTT5", "RTT6"].freeze
  46. 1 attr_reader :categories
  47. # コマンドを解釈し、結果を取得する
  48. # return [String]
  49. 1 def roll_command(randomizer, command)
  50. 1218 c = command
  51. 1218 then: 65 if ["RTT", @rtt].include?(c)
  52. 65 else: 1153 format_skill(@rtt_format, roll_skill(randomizer))
  53. 1153 then: 20 elsif ["RCT", @rct].include?(c)
  54. 20 cat = roll_category(randomizer)
  55. 20 else: 1133 format(@rct_format, category_dice: cat.dice, category_name: cat.name)
  56. 1133 then: 176 else: 957 elsif (index = RTTN.index(c)) || (index = @rttn.index(c))
  57. 176 format_skill(@rttn_format, @categories[index].roll(randomizer))
  58. end
  59. end
  60. # 1D6を振り、ランダムで分野を決定する
  61. # @return [SaiFicSkillTable::Category]
  62. 1 def roll_category(randomizer)
  63. 194 @categories[randomizer.roll_once(6) - 1]
  64. end
  65. # 1D6と2D6を振り、ランダムで特技を決定する
  66. # @return [SaiFicSkillTable::Skill]
  67. 1 def roll_skill(randomizer)
  68. 165 roll_category(randomizer).roll(randomizer)
  69. end
  70. 1 def prefixes
  71. 17 (["RTT[1-6]?", "RCT", @rtt, @rct] + @rttn).compact
  72. end
  73. 1 private
  74. 1 def format_skill(format_string, skill)
  75. 241 format(format_string, category_dice: skill.category_dice, row_dice: skill.row_dice, category_name: skill.category_name, skill_name: skill.name, text: skill.to_s)
  76. end
  77. end
  78. end
  79. end

lib/bcdice/dice_table/sai_fic_skill_table/category.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module DiceTable
  4. 1 class SaiFicSkillTable
  5. 1 class Category
  6. 1 def initialize(name, skills, dice, s_format)
  7. 138 @name = name
  8. 1656 @skills = skills.map.with_index(2) { |s, index| SaiFicSkillTable::Skill.new(name, s, dice, index, s_format) }
  9. 138 @dice = dice
  10. end
  11. 1 def roll(randomizer)
  12. 374 skills[randomizer.roll_sum(2, 6) - 2]
  13. end
  14. 1 def to_s
  15. 9 @name
  16. end
  17. 1 attr_reader :name, :dice, :skills
  18. end
  19. end
  20. end
  21. end

lib/bcdice/dice_table/sai_fic_skill_table/skill.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module DiceTable
  4. 1 class SaiFicSkillTable
  5. 1 class Skill
  6. 1 def initialize(category_name, skill_name, category_dice, row_dice, s_format)
  7. 1518 @category_name = category_name
  8. 1518 @name = skill_name
  9. 1518 @category_dice = category_dice
  10. 1518 @row_dice = row_dice
  11. 1518 @s_format = s_format
  12. end
  13. 1 def to_s
  14. 347 format(@s_format, category_dice: @category_dice, row_dice: @row_dice, category_name: @category_name, skill_name: @name)
  15. end
  16. 1 attr_reader :category_name, :name, :category_dice, :row_dice
  17. end
  18. end
  19. end
  20. end

lib/bcdice/dice_table/table.rb

95.0% lines covered

50.0% branches covered

20 relevant lines. 19 lines covered and 1 lines missed.
2 total branches, 1 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module DiceTable
  4. # 表を表すクラス
  5. 1 class Table
  6. # @param key [String]
  7. # @param locale [Symbol]
  8. # @return [Table]
  9. 1 def self.from_i18n(key, locale)
  10. 757 table = I18n.t(key, locale: locale)
  11. 757 new(table[:name], table[:type], table[:items])
  12. end
  13. # @param [String] name 表の名前
  14. # @param [String] type 項目を選ぶときのダイスロールの方法 '1D6'など
  15. # @param [Array<String>] items 表の項目の配列
  16. 1 def initialize(name, type, items)
  17. 1526 @name = name
  18. 1526 @items = items.freeze
  19. 1526 m = /(\d+)D(\d+)/i.match(type)
  20. 1526 else: 1526 then: 0 unless m
  21. raise ArgumentError, "Unexpected table type: #{type}"
  22. end
  23. 1526 @times = m[1].to_i
  24. 1526 @sides = m[2].to_i
  25. end
  26. # 表を振る
  27. # @param [BCDice] bcdice ランダマイザ
  28. # @return [String] 結果
  29. 1 def roll(bcdice)
  30. 2511 value = bcdice.roll_sum(@times, @sides)
  31. 2511 return choice(value)
  32. end
  33. 1 def choice(value)
  34. 2892 index = value - @times
  35. 2892 return RollResult.new(@name, value, @items[index])
  36. end
  37. end
  38. end
  39. end

lib/bcdice/enum.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. # D66のダイス入れ替え
  4. 1 module D66SortType
  5. 1 NO_SORT = :no_sort # 入れ替えない
  6. 1 ASC = :asc # 一の位が大きな出目になるよう、昇順にソートする
  7. 1 DESC = :desc # 一の位が小さな出目になるよう、降順にソートする
  8. end
  9. # 割り算をした後の端数の扱い
  10. 1 module RoundType
  11. 1 CEIL = :ceil # 切り上げ
  12. 1 FLOOR = :floor # 切り捨て
  13. 1 ROUND = :round # 四捨五入
  14. end
  15. end

lib/bcdice/format.rb

93.75% lines covered

90.0% branches covered

16 relevant lines. 15 lines covered and 1 lines missed.
10 total branches, 9 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module Format
  4. 1 module_function
  5. # 比較演算子を文字列表記にする
  6. #
  7. # @param op [Symbol]
  8. # @return [String, nil]
  9. 1 def comparison_operator(op)
  10. 387 else: 87 case op
  11. when: 3 when :==
  12. 3 "="
  13. when: 5 when :'!='
  14. 5 "<>"
  15. when: 292 when Symbol
  16. 292 op.to_s
  17. end
  18. end
  19. # 修正値を文字列表記にする
  20. #
  21. # @param number [Integer, nil]
  22. # @return [String]
  23. 1 def modifier(number)
  24. 3874 then: 0 if number.nil?
  25. else: 3874 nil
  26. 3874 then: 1582 elsif number == 0
  27. 1582 else: 2292 ""
  28. 2292 then: 1933 elsif number > 0
  29. 1933 "+#{number}"
  30. else: 359 else
  31. 359 number.to_s
  32. end
  33. end
  34. end
  35. end

lib/bcdice/game_system.rb

100.0% lines covered

100.0% branches covered

290 relevant lines. 290 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/AFF2e"
  3. 1 require "bcdice/game_system/AceKillerGene"
  4. 1 require "bcdice/game_system/Agnostos"
  5. 1 require "bcdice/game_system/Ainecadette"
  6. 1 require "bcdice/game_system/Aionia"
  7. 1 require "bcdice/game_system/Airgetlamh"
  8. 1 require "bcdice/game_system/AlchemiaStruggle"
  9. 1 require "bcdice/game_system/Alsetto"
  10. 1 require "bcdice/game_system/Alshard"
  11. 1 require "bcdice/game_system/AlterRaise"
  12. 1 require "bcdice/game_system/Amadeus"
  13. 1 require "bcdice/game_system/Amadeus_Korean"
  14. 1 require "bcdice/game_system/AngelGear"
  15. 1 require "bcdice/game_system/AnimaAnimus"
  16. 1 require "bcdice/game_system/AniMalus"
  17. 1 require "bcdice/game_system/Aoharubaan"
  18. 1 require "bcdice/game_system/Arianrhod"
  19. 1 require "bcdice/game_system/Arianrhod_Korean"
  20. 1 require "bcdice/game_system/ArknightsFan"
  21. 1 require "bcdice/game_system/ArsMagica"
  22. 1 require "bcdice/game_system/AssaultEngine"
  23. 1 require "bcdice/game_system/Avandner"
  24. 1 require "bcdice/game_system/Ayabito"
  25. 1 require "bcdice/game_system/Bakenokawa"
  26. 1 require "bcdice/game_system/BBN"
  27. 1 require "bcdice/game_system/BadLife"
  28. 1 require "bcdice/game_system/BarnaKronika"
  29. 1 require "bcdice/game_system/BattleTech"
  30. 1 require "bcdice/game_system/BeastBindTrinity"
  31. 1 require "bcdice/game_system/BeginningIdol"
  32. 1 require "bcdice/game_system/BeginningIdol_Korean"
  33. 1 require "bcdice/game_system/BeginningIdol2022"
  34. 1 require "bcdice/game_system/BlackJacket"
  35. 1 require "bcdice/game_system/BlackJacket_Korean"
  36. 1 require "bcdice/game_system/BladeOfArcana"
  37. 1 require "bcdice/game_system/BlindMythos"
  38. 1 require "bcdice/game_system/BloodCrusade"
  39. 1 require "bcdice/game_system/BloodMoon"
  40. 1 require "bcdice/game_system/Bloodorium"
  41. 1 require "bcdice/game_system/CardRanker"
  42. 1 require "bcdice/game_system/CastleInGray"
  43. 1 require "bcdice/game_system/ChaosFlare"
  44. 1 require "bcdice/game_system/CharonSanctions"
  45. 1 require "bcdice/game_system/Chill"
  46. 1 require "bcdice/game_system/Chill3"
  47. 1 require "bcdice/game_system/CodeLayerd"
  48. 1 require "bcdice/game_system/ColossalHunter"
  49. 1 require "bcdice/game_system/Comes"
  50. 1 require "bcdice/game_system/ConvictorDrive"
  51. 1 require "bcdice/game_system/CrashWorld"
  52. 1 require "bcdice/game_system/Cthulhu"
  53. 1 require "bcdice/game_system/Cthulhu7th"
  54. 1 require "bcdice/game_system/Cthulhu7th_ChineseTraditional"
  55. 1 require "bcdice/game_system/Cthulhu7th_Korean"
  56. 1 require "bcdice/game_system/CthulhuTech"
  57. 1 require "bcdice/game_system/Cthulhu_ChineseTraditional"
  58. 1 require "bcdice/game_system/Cthulhu_English"
  59. 1 require "bcdice/game_system/Cthulhu_Korean"
  60. 1 require "bcdice/game_system/Cthulhu_SimplifiedChinese"
  61. 1 require "bcdice/game_system/CyberpunkRed"
  62. 1 require "bcdice/game_system/CyberpunkRed_Korean"
  63. 1 require "bcdice/game_system/DarkBlaze"
  64. 1 require "bcdice/game_system/DarkDaysDrive"
  65. 1 require "bcdice/game_system/DarkSouls"
  66. 1 require "bcdice/game_system/DeadlineHeroes"
  67. 1 require "bcdice/game_system/DemonParasite"
  68. 1 require "bcdice/game_system/DemonSpike"
  69. 1 require "bcdice/game_system/DesperateRun"
  70. 1 require "bcdice/game_system/DetatokoSaga"
  71. 1 require "bcdice/game_system/DetatokoSaga_Korean"
  72. 1 require "bcdice/game_system/DiceBot"
  73. 1 require "bcdice/game_system/DiceOfTheDead"
  74. 1 require "bcdice/game_system/DivineCharger"
  75. 1 require "bcdice/game_system/DoubleCross"
  76. 1 require "bcdice/game_system/DoubleCross_Korean"
  77. 1 require "bcdice/game_system/Dracurouge"
  78. 1 require "bcdice/game_system/Dracurouge_Korean"
  79. 1 require "bcdice/game_system/DungeonsAndDragons"
  80. 1 require "bcdice/game_system/DungeonsAndDragons5"
  81. 1 require "bcdice/game_system/EarthDawn"
  82. 1 require "bcdice/game_system/EarthDawn3"
  83. 1 require "bcdice/game_system/EarthDawn4"
  84. 1 require "bcdice/game_system/EclipsePhase"
  85. 1 require "bcdice/game_system/Elric"
  86. 1 require "bcdice/game_system/Elysion"
  87. 1 require "bcdice/game_system/EmbryoMachine"
  88. 1 require "bcdice/game_system/Emoklore"
  89. 1 require "bcdice/game_system/EndBreaker"
  90. 1 require "bcdice/game_system/EtrianOdysseySRS"
  91. 1 require "bcdice/game_system/FateCoreSystem"
  92. 1 require "bcdice/game_system/Fiasco"
  93. 1 require "bcdice/game_system/Fiasco_Korean"
  94. 1 require "bcdice/game_system/FilledWith"
  95. 1 require "bcdice/game_system/FullMetalPanic"
  96. 1 require "bcdice/game_system/FullFace"
  97. 1 require "bcdice/game_system/FutariSousa"
  98. 1 require "bcdice/game_system/FutariSousa_Korean"
  99. 1 require "bcdice/game_system/Garako"
  100. 1 require "bcdice/game_system/GardenOrder"
  101. 1 require "bcdice/game_system/GehennaAn"
  102. 1 require "bcdice/game_system/GeishaGirlwithKatana"
  103. 1 require "bcdice/game_system/GhostLive"
  104. 1 require "bcdice/game_system/GoblinSlayer"
  105. 1 require "bcdice/game_system/GoldenSkyStories"
  106. 1 require "bcdice/game_system/Gorilla"
  107. 1 require "bcdice/game_system/GranCrest"
  108. 1 require "bcdice/game_system/GundamSentinel"
  109. 1 require "bcdice/game_system/Gundog"
  110. 1 require "bcdice/game_system/GundogRevised"
  111. 1 require "bcdice/game_system/GundogZero"
  112. 1 require "bcdice/game_system/GURPS"
  113. 1 require "bcdice/game_system/GurpsFW"
  114. 1 require "bcdice/game_system/HarnMaster"
  115. 1 require "bcdice/game_system/HatsuneMiku"
  116. 1 require "bcdice/game_system/HeroScale"
  117. 1 require "bcdice/game_system/Hieizan"
  118. 1 require "bcdice/game_system/HouraiGakuen"
  119. 1 require "bcdice/game_system/HuntersMoon"
  120. 1 require "bcdice/game_system/HunterTheReckoning5th"
  121. 1 require "bcdice/game_system/IfIfIf"
  122. 1 require "bcdice/game_system/Illusio"
  123. 1 require "bcdice/game_system/InfiniteBabeL"
  124. 1 require "bcdice/game_system/InfiniteFantasia"
  125. 1 require "bcdice/game_system/Insane"
  126. 1 require "bcdice/game_system/Insane_Korean"
  127. 1 require "bcdice/game_system/InvisibleLiar"
  128. 1 require "bcdice/game_system/Irisbane"
  129. 1 require "bcdice/game_system/IthaWenUa"
  130. 1 require "bcdice/game_system/JamesBond"
  131. 1 require "bcdice/game_system/JekyllAndHyde"
  132. 1 require "bcdice/game_system/JuinKansen"
  133. 1 require "bcdice/game_system/Kamigakari"
  134. 1 require "bcdice/game_system/Kamigakari_Korean"
  135. 1 require "bcdice/game_system/KamitsubakiCityUnderConstructionNarrative"
  136. 1 require "bcdice/game_system/KanColle"
  137. 1 require "bcdice/game_system/Karukami"
  138. 1 require "bcdice/game_system/KemonoNoMori"
  139. 1 require "bcdice/game_system/KillDeathBusiness"
  140. 1 require "bcdice/game_system/KillDeathBusiness_Korean"
  141. 1 require "bcdice/game_system/KimitoYell"
  142. 1 require "bcdice/game_system/KizunaBullet"
  143. 1 require "bcdice/game_system/KurayamiCrying"
  144. 1 require "bcdice/game_system/Kutulu"
  145. 1 require "bcdice/game_system/KyokoShinshoku"
  146. 1 require "bcdice/game_system/Liminal"
  147. 1 require "bcdice/game_system/LiveraDoll"
  148. 1 require "bcdice/game_system/LogHorizon"
  149. 1 require "bcdice/game_system/LogHorizon_Korean"
  150. 1 require "bcdice/game_system/LostRecord"
  151. 1 require "bcdice/game_system/LostRoyal"
  152. 1 require "bcdice/game_system/MagicaLogia"
  153. 1 require "bcdice/game_system/MagicaLogia_Korean"
  154. 1 require "bcdice/game_system/MagicaLogia_SimplifiedChinese"
  155. 1 require "bcdice/game_system/Magius"
  156. 1 require "bcdice/game_system/Magius_3rdNewTokyoCity"
  157. 1 require "bcdice/game_system/MamonoScramble"
  158. 1 require "bcdice/game_system/MeikyuDays"
  159. 1 require "bcdice/game_system/MeikyuKingdom"
  160. 1 require "bcdice/game_system/MeikyuKingdomBasic"
  161. 1 require "bcdice/game_system/MetalHead"
  162. 1 require "bcdice/game_system/MetalHeadExtream"
  163. 1 require "bcdice/game_system/MetallicGuardian"
  164. 1 require "bcdice/game_system/MonotoneMuseum"
  165. 1 require "bcdice/game_system/MonotoneMuseum_Korean"
  166. 1 require "bcdice/game_system/Nechronica"
  167. 1 require "bcdice/game_system/Nechronica_Korean"
  168. 1 require "bcdice/game_system/NervWhitePaper"
  169. 1 require "bcdice/game_system/NeverCloud"
  170. 1 require "bcdice/game_system/NightWizard"
  171. 1 require "bcdice/game_system/NightWizard3rd"
  172. 1 require "bcdice/game_system/NightmareHunterDeep"
  173. 1 require "bcdice/game_system/NinjaSlayer"
  174. 1 require "bcdice/game_system/NinjaSlayer2"
  175. 1 require "bcdice/game_system/NjslyrBattle"
  176. 1 require "bcdice/game_system/NobunagasBlackCastle"
  177. 1 require "bcdice/game_system/NRR"
  178. 1 require "bcdice/game_system/NSSQ"
  179. 1 require "bcdice/game_system/Nuekagami"
  180. 1 require "bcdice/game_system/OneWayHeroics"
  181. 1 require "bcdice/game_system/OracleEngine"
  182. 1 require "bcdice/game_system/OrgaRain"
  183. 1 require "bcdice/game_system/Oukahoushin3rd"
  184. 1 require "bcdice/game_system/Paradiso"
  185. 1 require "bcdice/game_system/Paranoia"
  186. 1 require "bcdice/game_system/ParanoiaRebooted"
  187. 1 require "bcdice/game_system/ParasiteBlood"
  188. 1 require "bcdice/game_system/PastFutureParadox"
  189. 1 require "bcdice/game_system/Pathfinder"
  190. 1 require "bcdice/game_system/Peekaboo"
  191. 1 require "bcdice/game_system/Pendragon"
  192. 1 require "bcdice/game_system/PersonaO"
  193. 1 require "bcdice/game_system/PhantasmAdventure"
  194. 1 require "bcdice/game_system/Postman"
  195. 1 require "bcdice/game_system/PulpCthulhu"
  196. 1 require "bcdice/game_system/Raisondetre"
  197. 1 require "bcdice/game_system/RecordOfLodossWar"
  198. 1 require "bcdice/game_system/RecordOfSteam"
  199. 1 require "bcdice/game_system/Revulture"
  200. 1 require "bcdice/game_system/RogueLikeHalf"
  201. 1 require "bcdice/game_system/RokumonSekai2"
  202. 1 require "bcdice/game_system/RoleMaster"
  203. 1 require "bcdice/game_system/RuinBreakers"
  204. 1 require "bcdice/game_system/RuneQuest"
  205. 1 require "bcdice/game_system/RuneQuestRoleplayingInGlorantha"
  206. 1 require "bcdice/game_system/RyuTuber"
  207. 1 require "bcdice/game_system/Ryutama"
  208. 1 require "bcdice/game_system/SajinsenkiAGuS"
  209. 1 require "bcdice/game_system/SajinsenkiAGuS2E"
  210. 1 require "bcdice/game_system/SRS"
  211. 1 require "bcdice/game_system/SamsaraBallad"
  212. 1 require "bcdice/game_system/Satasupe"
  213. 1 require "bcdice/game_system/ScreamHighSchool"
  214. 1 require "bcdice/game_system/Sengensyou"
  215. 1 require "bcdice/game_system/SevenFortressMobius"
  216. 1 require "bcdice/game_system/ShadowRun"
  217. 1 require "bcdice/game_system/ShadowRun4"
  218. 1 require "bcdice/game_system/ShadowRun5"
  219. 1 require "bcdice/game_system/SharedFantasia"
  220. 1 require "bcdice/game_system/ShinMegamiTenseiKakuseihen"
  221. 1 require "bcdice/game_system/ShinkuuGakuen"
  222. 1 require "bcdice/game_system/ShinobiGami"
  223. 1 require "bcdice/game_system/Shiranui"
  224. 1 require "bcdice/game_system/ShoujoTenrankai"
  225. 1 require "bcdice/game_system/ShuumatsuBargainWars"
  226. 1 require "bcdice/game_system/ShuumatsuKikou"
  227. 1 require "bcdice/game_system/Siren"
  228. 1 require "bcdice/game_system/Skynauts"
  229. 1 require "bcdice/game_system/SkynautsBouken"
  230. 1 require "bcdice/game_system/SkynautsBouken_Korean"
  231. 1 require "bcdice/game_system/StarryDolls"
  232. 1 require "bcdice/game_system/SteamPunkers"
  233. 1 require "bcdice/game_system/StellarKnights"
  234. 1 require "bcdice/game_system/StellarKnights_Korean"
  235. 1 require "bcdice/game_system/StellarLife"
  236. 1 require "bcdice/game_system/StrangerOfSwordCity"
  237. 1 require "bcdice/game_system/StratoShout"
  238. 1 require "bcdice/game_system/StratoShout_Korean"
  239. 1 require "bcdice/game_system/Strave"
  240. 1 require "bcdice/game_system/SwordWorld"
  241. 1 require "bcdice/game_system/SwordWorld2_0"
  242. 1 require "bcdice/game_system/SwordWorld2_5"
  243. 1 require "bcdice/game_system/SwordWorld_SimplifiedChinese"
  244. 1 require "bcdice/game_system/SwordWorld2_0_SimplifiedChinese"
  245. 1 require "bcdice/game_system/SwordWorld2_5_SimplifiedChinese"
  246. 1 require "bcdice/game_system/TalesFromTheLoop"
  247. 1 require "bcdice/game_system/TenkaRyouran"
  248. 1 require "bcdice/game_system/TensaiGunshiNiNaro"
  249. 1 require "bcdice/game_system/TheIndieHack"
  250. 1 require "bcdice/game_system/TheOneRing2nd"
  251. 1 require "bcdice/game_system/TherapieSein"
  252. 1 require "bcdice/game_system/TheUnofficialHollowKnightRPG"
  253. 1 require "bcdice/game_system/TokumeiTenkousei"
  254. 1 require "bcdice/game_system/TokyoGhostResearch"
  255. 1 require "bcdice/game_system/TokyoNova"
  256. 1 require "bcdice/game_system/Torg"
  257. 1 require "bcdice/game_system/Torg1_5"
  258. 1 require "bcdice/game_system/TorgEternity"
  259. 1 require "bcdice/game_system/ToshiakiHolyGrailWar"
  260. 1 require "bcdice/game_system/TrailOfCthulhu"
  261. 1 require "bcdice/game_system/TrinitySeven"
  262. 1 require "bcdice/game_system/TunnelsAndTrolls"
  263. 1 require "bcdice/game_system/TwilightGunsmoke"
  264. 1 require "bcdice/game_system/UnsungDuet"
  265. 1 require "bcdice/game_system/UnsungDuet_Korean"
  266. 1 require "bcdice/game_system/Utakaze"
  267. 1 require "bcdice/game_system/VampireTheMasquerade5th"
  268. 1 require "bcdice/game_system/Ventangle"
  269. 1 require "bcdice/game_system/Ventangle_Korean"
  270. 1 require "bcdice/game_system/Villaciel"
  271. 1 require "bcdice/game_system/VisionConnect"
  272. 1 require "bcdice/game_system/WARPS"
  273. 1 require "bcdice/game_system/WaresBlade"
  274. 1 require "bcdice/game_system/Warhammer"
  275. 1 require "bcdice/game_system/Warhammer4"
  276. 1 require "bcdice/game_system/WerewolfTheApocalypse5th"
  277. 1 require "bcdice/game_system/WitchQuest"
  278. 1 require "bcdice/game_system/WorldOfDarkness"
  279. 1 require "bcdice/game_system/WorldsEndFrontline"
  280. 1 require "bcdice/game_system/YankeeMustDie"
  281. 1 require "bcdice/game_system/YankeeYogSothoth"
  282. 1 require "bcdice/game_system/YearZeroEngine"
  283. 1 require "bcdice/game_system/Yggdrasill"
  284. 1 require "bcdice/game_system/Yotabana"
  285. 1 require "bcdice/game_system/YuMyoKishi"
  286. 1 require "bcdice/game_system/ZettaiReido"
  287. 1 require "bcdice/game_system/ZombiLine"
  288. 1 require "bcdice/game_system/FinalFantasyXIV"
  289. 1 require "bcdice/game_system/FinalFantasyXIV_English"
  290. 1 require "bcdice/game_system/Garactier"
  291. 1 require "bcdice/game_system/WoW"

lib/bcdice/game_system/AFF2e.rb

98.61% lines covered

91.67% branches covered

72 relevant lines. 71 lines covered and 1 lines missed.
24 total branches, 22 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class AFF2e < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'AFF2e'
  7. # ゲームシステム名
  8. 1 NAME = 'ADVANCED FIGHTING FANTASY 2nd Edition'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'あとはんすとふあいていんくふあんたしい2'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. 対抗なしロール\tFF{目標値}+{補正}
  14. 対抗ロール\tFR{能力値}+{補正}
  15. 武器ロール\tFD[2,3,3,3,3,3,4]+{補正}
  16. 防具ロール\tFD[0,0,0,0,1+1,1+1,2+2]+{補正}
  17. MESSAGETEXT
  18. # ダイスボットで使用するコマンドを配列で列挙する
  19. 1 register_prefix('FF.+', 'FR.+', 'FD.+')
  20. 1 def explicit_sign(i)
  21. 18 format('%+d', i)
  22. end
  23. 1 def eval_term(term)
  24. 53 value = 0
  25. 53 term.scan(/[+-]?\d+/) do |fact|
  26. 63 value += fact.to_i
  27. end
  28. 53 value
  29. end
  30. 1 def parentheses(str)
  31. 17 '(' + str + ')'
  32. end
  33. 1 def successful_or_failed(total, diff)
  34. 8 case total
  35. when: 2 when 2
  36. 2 then: 1 else: 1 diff <= 1 ? '成功(大成功ではない)' : '大成功!'
  37. when: 2 when 12
  38. 2 then: 1 else: 1 diff >= 12 ? '失敗(大失敗ではない)' : '大失敗!'
  39. else: 4 else
  40. 4 then: 2 else: 2 total <= diff ? '成功' : '失敗'
  41. end
  42. end
  43. 1 def critical(total)
  44. 4 else: 2 case total
  45. when: 1 when 2
  46. 1 'ファンブル!'
  47. when: 1 when 12
  48. 1 '強打!'
  49. end
  50. end
  51. 1 def clamp(i, min, max)
  52. 5 then: 0 if i < min
  53. else: 5 min
  54. 5 then: 2 elsif i > max
  55. 2 max
  56. else: 3 else
  57. 3 i
  58. end
  59. end
  60. 1 def eval_game_system_specific_command(command)
  61. 19 else: 0 case command
  62. when /\AFF/
  63. # 対抗なしロール
  64. # '成功' or '失敗' を出力する
  65. when: 8 #
  66. 8 md = Regexp.last_match
  67. 8 term = md.post_match
  68. # 目標値
  69. 8 diff = eval_term(term)
  70. 8 dice_command = "2D6<=#{diff}"
  71. 8 dice_list = @randomizer.roll_barabara(2, 6)
  72. 8 total = dice_list.sum()
  73. 8 dice_str = dice_list.join(",")
  74. 8 expr = "#{total}[#{dice_str}]"
  75. 8 succ = successful_or_failed(total, diff)
  76. 8 sequence = [parentheses(dice_command), expr, succ]
  77. when /\AFR/
  78. # 対抗ロール
  79. # 値を出力する
  80. when: 4 #
  81. 4 md = Regexp.last_match
  82. 4 term = md.post_match
  83. # 補正値
  84. 4 corr = eval_term(term)
  85. 4 dice_command = "2D6#{explicit_sign corr}"
  86. 4 dice_list = @randomizer.roll_barabara(2, 6)
  87. 4 total = dice_list.sum()
  88. 4 dice_str = dice_list.join(",")
  89. 4 expr = "#{total}[#{dice_str}]#{explicit_sign corr}"
  90. 4 crit = critical(total)
  91. 4 sequence = [parentheses(dice_command), expr, crit, total + corr].compact
  92. when /\AFD/
  93. # 武器防具ロール
  94. # ダメージを出力する
  95. when: 7 #
  96. 7 md = Regexp.last_match
  97. 7 term = md.post_match
  98. 7 md = /\A\[(.+)\]/.match(term)
  99. 7 else: 6 then: 1 unless md
  100. 1 return 'ダメージスロットは必須です。'
  101. end
  102. 6 term = md.post_match
  103. 42 damage_slots = md[1].split(',').map { |t| eval_term(t) }
  104. 6 then: 1 else: 5 if damage_slots.size != 7
  105. 1 return 'ダメージスロットの長さに誤りがあります。'
  106. end
  107. # 補正値
  108. 5 corr = eval_term(term)
  109. 5 dice_command = "1D6#{explicit_sign corr}"
  110. 5 total = @randomizer.roll_once(6)
  111. 5 expr = "#{total}#{explicit_sign corr}"
  112. 5 slot_number = clamp(total + corr, 1, 7)
  113. 5 damage = damage_slots[slot_number - 1]
  114. 5 sequence = [parentheses(dice_command), expr, total + corr, "#{damage}ダメージ"]
  115. end
  116. 17 result = sequence.join(' > ')
  117. 17 return result
  118. end
  119. end
  120. end
  121. end

lib/bcdice/game_system/AceKillerGene.rb

95.0% lines covered

66.67% branches covered

20 relevant lines. 19 lines covered and 1 lines missed.
3 total branches, 2 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/GardenOrder'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class AceKillerGene < GardenOrder
  6. # ゲームシステムの識別子
  7. 1 ID = 'AceKillerGene'
  8. # ゲームシステム名
  9. 1 NAME = 'エースキラージーン'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'ええすきらあしいん'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・基本判定
  15.  AKx/y@z x:成功率、y:連続攻撃回数(省略可)、z:クリティカル値(省略可)
  16.  (連続攻撃では1回の判定のみが実施されます)
  17.  例)AK55 AK100/2 AK70@10 AK155/3@44
  18. ・負傷表
  19.  DCxxy
  20.  xx:属性(切断:SL,銃弾:BL,衝撃:IM,灼熱:BR,冷却:RF,電撃:EL)
  21.  y:ダメージ
  22.  例)DCSL7 DCEL22
  23. INFO_MESSAGE_TEXT
  24. 1 register_prefix(
  25. '(AK|AKG)',
  26. 'DC(SL|BL|IM|BR|RF|EL).+'
  27. )
  28. 1 def eval_game_system_specific_command(command)
  29. 43 else: 0 case command
  30. when: 34 when %r{(AK|AKG)(-?\d+)(/(\d+))?(@(\d+))?}i
  31. 34 success_rate = Regexp.last_match(2).to_i
  32. 34 repeat_count = (Regexp.last_match(4) || 1).to_i
  33. 34 critical_border_text = Regexp.last_match(6)
  34. 34 critical_border = get_critical_border(critical_border_text, success_rate)
  35. 34 return check_roll_repeat_attack(success_rate, repeat_count, critical_border)
  36. when: 9 when /^DC(SL|BL|IM|BR|RF|EL)(\d+)/i
  37. 9 type = Regexp.last_match(1)
  38. 9 damage_value = Regexp.last_match(2).to_i
  39. 9 return look_up_damage_chart(type, damage_value)
  40. end
  41. return nil
  42. end
  43. end
  44. end
  45. end

lib/bcdice/game_system/Agnostos.rb

99.12% lines covered

98.15% branches covered

114 relevant lines. 113 lines covered and 1 lines missed.
54 total branches, 53 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Agnostos < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "Agnostos"
  7. # ゲームシステム名
  8. 1 NAME = "アグノストス"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "あくのすとす"
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ■ 行為判定
  14. CDx>=t
  15. x: コンディションレベル(A~E もしくは 5~1)
  16. t: 目標値
  17. の成否とコンディションの変動量を判定します。
  18. ■ 心拍のコンディションチェック
  19. HCDx
  20. x: コンディションレベル(C+, B+, A, B-, C-, もしくは 5~1)
  21. 酸素の消費量、コンディションの変動量、気絶したかを判定します。
  22. ■ 必殺技
  23. xSPy
  24. x: メインコンディション(A~E もしくは 5~1)
  25. y: サブコンディション(A~E もしくは 5~1)
  26. 必殺技のダメージ量を判定します。
  27. MESSAGETEXT
  28. 1 register_prefix('CD', 'HCD', '[A-E1-5]SP[A-E1-5]')
  29. 1 def eval_game_system_specific_command(command)
  30. 41 condition_roll(command) || heart_condition_roll(command) || special_roll(command)
  31. end
  32. 1 private
  33. # コンディションチェック
  34. 1 def condition_roll(command)
  35. 41 parser = Command::Parser.new(/CD[A-E1-5]/, round_type: @round_type).disable_modifier.restrict_cmp_op_to(:>=)
  36. 41 parsed = parser.parse(command)
  37. 41 else: 18 then: 23 unless parsed
  38. 23 return nil
  39. end
  40. 18 condition_level = to_condition_level(parsed.command[-1])
  41. 18 sides = to_sides(condition_level)
  42. 18 value = @randomizer.roll_once(sides)
  43. 18 Result.new.tap do |r|
  44. 18 r.critical = critical?(sides, value)
  45. 18 r.fumble = fumble?(sides, value)
  46. 18 r.condition = value >= parsed.target_number
  47. 18 r.text = [
  48. "(CD#{condition_level}>=#{parsed.target_number})",
  49. "(1D#{sides}>=#{parsed.target_number})",
  50. value.to_s(),
  51. 18 then: 12 else: 6 r.success? ? "成功" : "失敗",
  52. condition_change(sides, value),
  53. ].join(" > ")
  54. end
  55. end
  56. 1 def to_condition_level(char)
  57. 30 case char
  58. when: 2 when "5"
  59. 2 "A"
  60. when: 1 when "4"
  61. 1 "B"
  62. when: 1 when "3"
  63. 1 "C"
  64. when: 1 when "2"
  65. 1 "D"
  66. when: 2 when "1"
  67. 2 "E"
  68. else: 23 else
  69. 23 char
  70. end
  71. end
  72. 1 def to_sides(condition)
  73. 24 case condition
  74. when: 4 when "A"
  75. 4 12
  76. when: 10 when "B"
  77. 10 10
  78. when: 3 when "C"
  79. 3 8
  80. when: 3 when "D"
  81. 3 6
  82. else: 4 else # "E"
  83. 4 4
  84. end
  85. end
  86. 1 def condition_change(sides, value)
  87. 30 then: 4 if critical?(sides, value)
  88. 4 else: 26 "コンディション:2段階上昇(クリティカル)"
  89. 26 then: 2 elsif fumble?(sides, value)
  90. 2 else: 24 "コンディション:2段階下降(ファンブル)"
  91. 24 then: 5 elsif sides != 12 && sides - value <= 1
  92. 5 else: 19 "コンディション:1段階上昇"
  93. 19 then: 2 elsif sides == 12 && value <= 6
  94. 2 else: 17 "コンディション:1段階下降"
  95. 17 then: 2 elsif sides == 10 && value <= 3
  96. 2 else: 15 "コンディション:1段階下降"
  97. 15 then: 1 elsif sides == 8 && value <= 2
  98. 1 "コンディション:1段階下降"
  99. else: 14 else
  100. 14 "コンディション:変動なし"
  101. end
  102. end
  103. 1 def critical?(sides, value)
  104. 65 sides != 12 && sides == value
  105. end
  106. 1 def fumble?(sides, value)
  107. 61 sides != 4 && value == 1
  108. end
  109. # 心拍のコンディションチェック
  110. 1 def heart_condition_roll(command)
  111. 23 m = /^HCD([A1-5]|[BC][+-])$/.match(command)
  112. 23 else: 17 then: 6 unless m
  113. 6 return nil
  114. end
  115. 17 suffix = m[1]
  116. 17 condition_level = to_heart_condition_level(suffix)
  117. 17 sides = to_heart_sides(condition_level)
  118. 17 value = @randomizer.roll_once(sides)
  119. 17 Result.new.tap do |r|
  120. 17 r.critical = critical?(sides, value)
  121. 17 r.fumble = fumble?(sides, value)
  122. 17 r.text = [
  123. "(HCD#{condition_level})",
  124. "(1D#{sides})",
  125. value.to_s(),
  126. heart_condition_change(sides, value),
  127. ].join(" > ")
  128. end
  129. end
  130. 1 def to_heart_condition_level(char)
  131. 17 case char
  132. when: 1 when "5"
  133. 1 "C+"
  134. when: 1 when "4"
  135. 1 "B+"
  136. when: 1 when "3"
  137. 1 "A"
  138. when: 1 when "2"
  139. 1 "B-"
  140. when: 2 when "1"
  141. 2 "C-"
  142. else: 11 else
  143. 11 char
  144. end
  145. end
  146. 1 def to_heart_sides(condition)
  147. 17 case condition
  148. when: 2 when "C+"
  149. 2 12
  150. when: 3 when "B+"
  151. 3 10
  152. when: 6 when "A"
  153. 6 8
  154. when: 3 when "B-"
  155. 3 6
  156. else: 3 else # "C-"
  157. 3 4
  158. end
  159. end
  160. 1 def fainted?(sides, value)
  161. 17 case sides
  162. when: 2 when 12
  163. 2 value >= 7
  164. when: 3 when 10
  165. 3 value >= 10
  166. when: 6 when 8
  167. 6 false
  168. when: 3 when 6
  169. 3 value <= 1
  170. else: 3 else # 4
  171. 3 value <= 2
  172. end
  173. end
  174. 1 def heart_condition_change(sides, value)
  175. 17 then: 5 if fainted?(sides, value)
  176. 5 "気絶"
  177. else: 12 else
  178. 12 condition_change(sides, value)
  179. end
  180. end
  181. # 必殺技
  182. 1 def special_roll(command)
  183. 6 m = /^([A-E1-5])SP([A-E1-5])$/.match(command)
  184. 6 else: 6 then: 0 unless m
  185. return nil
  186. end
  187. 6 times_conditon_level = to_condition_level(m[1])
  188. 6 sides_conditon_level = to_condition_level(m[2])
  189. 6 times = to_times(times_conditon_level)
  190. 6 sides = to_sides(sides_conditon_level)
  191. 6 dice_list = @randomizer.roll_barabara(times, sides)
  192. 6 value = dice_list.sum()
  193. return [
  194. 6 "(#{times_conditon_level}SP#{sides_conditon_level})",
  195. "(#{times}D#{sides})",
  196. "#{value}[#{dice_list.join(',')}]",
  197. value.to_s(),
  198. ].join(" > ")
  199. end
  200. 1 def to_times(condition)
  201. 6 case condition
  202. when: 2 when "A"
  203. 2 5
  204. when: 1 when "B"
  205. 1 4
  206. when: 1 when "C"
  207. 1 3
  208. when: 1 when "D"
  209. 1 2
  210. else: 1 else # "E"
  211. 1 1
  212. end
  213. end
  214. end
  215. end
  216. end

lib/bcdice/game_system/Ainecadette.rb

100.0% lines covered

88.89% branches covered

33 relevant lines. 33 lines covered and 0 lines missed.
18 total branches, 16 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Ainecadette < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "Ainecadette"
  7. # ゲームシステム名
  8. 1 NAME = "エネカデット"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "えねかてつと"
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ■ 判定
  14. - 先輩 (AI) 10面ダイスを2つ振って判定します。『有利』なら【3AI】、『不利』なら【1AI】を使います。
  15. - 後輩 (CA) 6面ダイスを2つ振って判定します。『有利』なら【3CA】、『不利』なら【1CA】を使います。
  16. MESSAGETEXT
  17. 1 register_prefix('(\d+)?AI', '(\d+)?CA')
  18. 1 def eval_game_system_specific_command(command)
  19. 19 roll_action(command)
  20. end
  21. 1 private
  22. # 成功の目標値
  23. 1 SUCCESS_THRESHOLD = 4
  24. # スペシャルとなる出目
  25. 1 SPECIAL_DICE = 6
  26. 1 def roll_action(command)
  27. 19 m = /^(\d+)?(AI|CA)$/.match(command)
  28. 19 else: 19 then: 0 return nil unless m
  29. 19 is_senpai = m[2] == "AI"
  30. 19 then: 10 else: 9 times = m[1]&.to_i || 2
  31. 19 then: 10 else: 9 sides = is_senpai ? 10 : 6
  32. 19 then: 0 else: 19 return nil if times <= 0
  33. 19 dice_list = @randomizer.roll_barabara(times, sides)
  34. 19 max = dice_list.max
  35. result =
  36. 19 then: 2 if max <= 1
  37. 2 else: 17 Result.fumble("ファンブル(もやもやカウンターを2個獲得)")
  38. 17 then: 2 elsif dice_list.include?(6)
  39. 2 then: 1 else: 1 me = is_senpai ? "先輩" : "後輩"
  40. 2 then: 1 else: 1 target = is_senpai ? "後輩" : "先輩"
  41. 2 else: 15 Result.critical("スペシャル(絆カウンターを1個獲得し、#{target}は#{me}への感情を1つ獲得)")
  42. 15 then: 9 elsif max >= SUCCESS_THRESHOLD
  43. 9 Result.success("成功")
  44. else: 6 else
  45. 6 Result.failure("失敗")
  46. end
  47. 19 result.text = "(#{command}) > [#{dice_list.join(',')}] > #{result.text}"
  48. 19 return result
  49. end
  50. end
  51. end
  52. end

lib/bcdice/game_system/Aionia.rb

100.0% lines covered

96.67% branches covered

73 relevant lines. 73 lines covered and 0 lines missed.
30 total branches, 29 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Aionia < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "Aionia"
  7. # ゲームシステム名
  8. 1 NAME = "慈悲なきアイオニア"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "しひなきあいおにあ"
  11. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  12. - 技能判定(クリティカル・ファンブルなし)
  13. AB{n}>={dif} n=10面ダイスの数、dif=難易度
  14. - 技能判定(クリティカル・ファンブルあり)
  15. ABT{n}>={dif} n=10面ダイスの数、dif=難易度
  16. 例:AB2>=5 (一般技能を活用して難易度5の技能判定。 クリファンなし。)
  17. 例:ABT3>=15 (専門技能を活用して難易度15の技能判定。クリファンあり。)
  18. 例:AB1+2>=8 (一般技能を活用せず難易度8の技能判定。 ボーナスとして+2点の補正あり。 クリファンなし。)
  19. 例:ABT3-3>=10 (専門技能を活用して難易度10の技能判定。ペナルティとして-3点の補正あり。クリファンあり。)
  20. 例:ABT2>=4/8/12 (一般技能を活用して難易度4/8/12の段階的な技能判定。クリファンあり。)
  21. INFO_MESSAGE_TEXT
  22. 1 register_prefix('ABT?\d+([\+\-]\d+)?>=\d+(\/\d+)*')
  23. 1 def eval_game_system_specific_command(command)
  24. 74 return roll_skills(command)
  25. end
  26. 1 def roll_skills(command)
  27. 74 m = %r{AB(T?)(\d+)([+-]\d+)?>=((\d+)((/\d+)*))}.match(command)
  28. 74 else: 74 then: 0 return nil unless m
  29. # 値の取得
  30. 74 use_cf = m[1] != ''
  31. 74 times = m[2].to_i
  32. 74 bonus = m[3].to_i
  33. 74 targets = m[4].split('/').map(&:to_i)
  34. 74 target = targets[0]
  35. 74 min_target = targets.min
  36. 74 max_target = targets.max
  37. # ダイスロール
  38. 74 dice_list = @randomizer.roll_barabara(times, 10)
  39. 74 dice_total = dice_list.sum
  40. 74 total = dice_total + bonus
  41. # Result用変数宣言
  42. 74 is_success = false
  43. 74 has_critical = false
  44. 74 has_fumble = false
  45. # 結果判定
  46. # 難易度が一つの場合
  47. 74 then: 52 if targets.count == 1
  48. 52 then: 23 if total >= target
  49. 23 is_success = true
  50. 23 then: 3 if total >= target + 20 && use_cf
  51. 3 result = 'クリティカル'
  52. 3 else: 20 has_critical = true
  53. 20 then: 6 elsif target <= times
  54. 6 result = '自動成功'
  55. else: 14 else
  56. 14 result = '成功'
  57. end
  58. else: 29 else
  59. 29 is_success = false
  60. 29 then: 8 if dice_list.count(1) == times && use_cf
  61. 8 result = 'ファンブル'
  62. 8 else: 21 has_fumble = true
  63. 21 then: 6 elsif target > 10 * times
  64. 6 result = '自動失敗'
  65. else: 15 else
  66. 15 result = '失敗'
  67. end
  68. end
  69. # 段階的な難易度判定の場合
  70. else: 22 else
  71. 22 then: 17 if total >= min_target
  72. 17 is_success = true
  73. 17 then: 2 if total >= max_target + 20 && use_cf
  74. 2 result = 'クリティカル'
  75. 2 else: 15 has_critical = true
  76. 15 then: 1 elsif max_target <= times
  77. 1 else: 14 result = '自動成功'
  78. 14 then: 3 elsif total >= max_target
  79. 3 result = '全成功'
  80. else: 11 else
  81. 55 times_suc = targets.count { |x| x <= total }
  82. 11 result = "#{times_suc}段階成功"
  83. end
  84. else: 5 else
  85. 5 is_success = false
  86. 5 then: 1 if dice_list.count(1) == times && use_cf
  87. 1 result = 'ファンブル'
  88. 1 else: 4 has_fumble = true
  89. 4 then: 2 elsif min_target > 10 * times
  90. 2 result = '自動失敗'
  91. else: 2 else
  92. 2 result = '失敗'
  93. end
  94. end
  95. end
  96. # ボーナスがある場合の処理
  97. 74 bonus_text = ''
  98. 74 bonus_result = ''
  99. 74 then: 21 else: 53 if bonus != 0
  100. 21 then: 13 else: 8 if bonus > 0
  101. 13 bonus_text = "+"
  102. end
  103. 21 bonus_text += bonus.to_s
  104. 21 bonus_result = "#{total} > "
  105. end
  106. # Resultクラスに結果を入れる
  107. 74 Result.new.tap do |r|
  108. 74 r.text = "(#{command}) > #{dice_total}[#{dice_list.join(',')}]#{bonus_text} > #{bonus_result}#{result}"
  109. 74 r.critical = has_critical
  110. 74 r.fumble = has_fumble
  111. 74 r.success = is_success
  112. 74 r.failure = !is_success
  113. end
  114. end
  115. end
  116. end
  117. end

lib/bcdice/game_system/Airgetlamh.rb

97.96% lines covered

86.67% branches covered

49 relevant lines. 48 lines covered and 1 lines missed.
15 total branches, 13 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Airgetlamh < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Airgetlamh'
  7. # ゲームシステム名
  8. 1 NAME = '朱の孤塔のエアゲトラム'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'あけのことうのえあけとらむ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. 【Reg2.0『THE ANSWERER』~】
  14. ・調査判定(成功数を表示):[n]AA[m]
  15. ・命中判定(ダメージ表示):[n]AA[m]*p[+t][Cx]
  16. 【~Reg1.1『昇華』】
  17. ・調査判定(成功数を表示):[n]AL[m]
  18. ・命中判定(ダメージ表示):[n]AL[m]*p
  19. ----------------------------------------
  20. []内のコマンドは省略可能。
  21. 「n」でダイス数(攻撃回数)を指定。省略時は「2」。
  22. 「m」で目標値を指定。省略時は「6」。
  23. 「p」で威力を指定。「*」は「x」で代用可。
  24. 「+t」でクリティカルトリガーを指定。省略可。
  25. 「Cx」でクリティカル値を指定。省略時は「1」、最大値は「3」、「0」でクリティカル無し。
  26. 攻撃力指定で命中判定となり、成功数ではなく、ダメージを結果表示します。
  27. クリティカルヒットの分だけ、自動で振り足し処理を行います。
  28. (ALコマンドではクリティカル処理を行いません)
  29. 【書式例】
  30. ・AL → 2d10で目標値6の調査判定。
  31. ・5AA7*12 → 5d10で目標値7、威力12の命中判定。
  32. ・AA7x28+5 → 2d10で目標値7、威力28、クリティカルトリガー5の命中判定。
  33. ・9aa5*10C2 → 9d10で目標値5、威力10、クリティカル値2の命中判定。
  34. ・15AAx4c0 → 15d10で目標値6、威力4、クリティカル無しの命中判定。
  35. MESSAGETEXT
  36. 1 register_prefix(
  37. '\d*A[AL]'
  38. )
  39. 1 def initialize(command)
  40. 29 super(command)
  41. 29 @sort_add_dice = true # ダイスのソート有
  42. end
  43. 1 def eval_game_system_specific_command(command)
  44. # AA/ALコマンド:調査判定, 成功判定
  45. 29 then: 29 else: 0 if command =~ /(\d+)?A(A|L)(\d+)?((x|\*)(\d+)(\+(\d+))?)?(C(\d+))?$/i
  46. 29 diceCount = (Regexp.last_match(1) || 2).to_i
  47. 29 target = (Regexp.last_match(3) || 6).to_i
  48. 29 damage = (Regexp.last_match(6) || 0).to_i
  49. 29 then: 7 if Regexp.last_match(2) == 'L' # 旧Ver対応
  50. 7 criticalTrigger = 0
  51. 7 criticalNumber = 0
  52. else: 22 else
  53. 22 criticalTrigger = (Regexp.last_match(8) || 0).to_i
  54. 22 criticalNumber = (Regexp.last_match(10) || 1).to_i
  55. end
  56. 29 then: 0 else: 29 criticalNumber = 3 if criticalNumber > 4
  57. 29 return checkRoll(diceCount, target, damage, criticalTrigger, criticalNumber)
  58. end
  59. return nil
  60. end
  61. 1 def checkRoll(diceCount, target, damage, criticalTrigger, criticalNumber)
  62. 29 totalSuccessCount = 0
  63. 29 totalCriticalCount = 0
  64. 29 text = ""
  65. 29 rollCount = diceCount
  66. 29 body: 40 while rollCount > 0
  67. 40 diceArray = @randomizer.roll_barabara(rollCount, 10).sort
  68. 40 diceText = diceArray.join(",")
  69. 191 successCount = diceArray.count { |i| i <= target }
  70. 191 criticalCount = diceArray.count { |i| i <= criticalNumber }
  71. 40 totalSuccessCount += successCount
  72. 40 totalCriticalCount += criticalCount
  73. 40 else: 29 then: 11 text += "+" unless text.empty?
  74. 40 text += "#{successCount}[#{diceText}]"
  75. 40 rollCount = criticalCount
  76. end
  77. 29 result = ""
  78. 29 isDamage = (damage != 0)
  79. 29 then: 18 if isDamage
  80. 18 totalDamage = totalSuccessCount * damage + totalCriticalCount * criticalTrigger
  81. 18 result += "(#{diceCount}D10\<\=#{target}) > #{text} > Hits:#{totalSuccessCount}*#{damage}"
  82. 18 then: 4 else: 14 result += " + Trigger:#{totalCriticalCount}*#{criticalTrigger}" if criticalTrigger > 0
  83. 18 result += " > #{totalDamage}ダメージ"
  84. else: 11 else
  85. 11 result += "(#{diceCount}D10\<\=#{target}) > #{text} > 成功数:#{totalSuccessCount}"
  86. end
  87. 29 then: 9 else: 20 result += " / #{totalCriticalCount}クリティカル" if totalCriticalCount > 0
  88. 29 return result
  89. end
  90. end
  91. end
  92. end

lib/bcdice/game_system/AlchemiaStruggle.rb

100.0% lines covered

100.0% branches covered

62 relevant lines. 62 lines covered and 0 lines missed.
8 total branches, 8 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/base"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class AlchemiaStruggle < Base
  6. 1 ID = "AlchemiaStruggle"
  7. 1 NAME = "アルケミア・ストラグル"
  8. 1 SORT_KEY = "あるけみあすとらくる"
  9. 1 HELP_MESSAGE = <<~MESSAGETEXT
  10. ■ ダイスロール( xAS )
  11. xDをロールします。
  12. 例) 5AS
  13. ■ ダイスロール&最大になるようにピック( xASy )
  14. xDをロールし、そこから最大になるようにy個をピックします。
  15. 例) 4AS3
  16. ■ ウルダイスの獲得( xUL )
  17. xDのウルダイスを振り、出た出目の個数をNo.ごとにカウントします。
  18. 例) 6UL
  19. ■ 表
  20. ・奇跡の触媒
  21. ・エレメント (CELE, CElement)
  22. ・アルケミア (CALC, CAlchemia)
  23. ・インフォーマント (CINF, CInformant)
  24. ・イノセンス (CINN, CInnocence)
  25. ・アクワイヤード (CACQ, CAcquired)
  26. ・携行品
  27. ・Sサイズ (ARS, ArticleS)
  28. ・Mサイズ (ARM, ArticleM)
  29. ・Lサイズ (ARL, ArticleL)
  30. ・PC情報獲得表 (PCI, PCInformation)
  31. ・理由表 (REA, Reason)
  32. ・交流表 (ASS, Associate)
  33. ・接触のきっかけ表 (CON, Contact)
  34. MESSAGETEXT
  35. 1 ROLL_REG = /^(\d+)AS(\d+)?$/i.freeze
  36. 1 register_prefix('\d+AS', '\d+UL')
  37. 1 def initialize(command)
  38. 44 super(command)
  39. 44 @sort_add_dice = true # 加算ダイスのソート有
  40. 44 @sort_barabara_dice = true # バラバラダイスでソート有
  41. 44 @round_type = RoundType::CEIL # 割り算をした時の端数切り上げ
  42. end
  43. 1 def eval_game_system_specific_command(command)
  44. 41 c = ALIAS[command] || command
  45. 41 try_roll_alchemia(c) ||
  46. try_roll_uldice(c) ||
  47. roll_tables(c, TABLES)
  48. end
  49. 1 def try_roll_alchemia(command)
  50. 41 match = ROLL_REG.match(command)
  51. 41 else: 4 then: 37 return nil unless match
  52. 4 roll_dice_count = match[1].to_i
  53. 4 if match[2].nil?
  54. # ロールのみ(ピックなし):
  55. then: 1
  56. 1 result = roll_alchemia(roll_dice_count)
  57. 1 return make_roll_text(result)
  58. else
  59. # ロールして最大値をピック:
  60. else: 3
  61. 3 pick_dice_count = match[2].to_i
  62. 3 result = roll_alchemia_and_pick(roll_dice_count, pick_dice_count)
  63. 3 return make_roll_and_pick_text(result[:rolled_dices], pick_dice_count, result[:picked_dices])
  64. end
  65. end
  66. 1 def try_roll_uldice(command)
  67. 37 match = /^(\d+)UL$/.match(command)
  68. 37 else: 1 then: 36 return nil unless match
  69. 1 roll_dice_count = match[1].to_i
  70. 1 dice_list = @randomizer.roll_barabara(roll_dice_count, 6).sort
  71. 1 dice_list_text = dice_list.join(",")
  72. 1 result = dice_list.group_by(&:itself)
  73. 4 .map { |k, v| "No.#{k}: #{v.size}個" }
  74. .join(", ")
  75. sequence = [
  76. 1 "(#{roll_dice_count}D6)",
  77. "[#{dice_list_text}]",
  78. result
  79. ]
  80. 1 sequence.join(" > ")
  81. end
  82. 1 def roll_alchemia(roll_dice_count)
  83. 4 @randomizer.roll_barabara(roll_dice_count, 6)
  84. end
  85. 1 def roll_alchemia_and_pick(roll_dice_count, pick_dice_count)
  86. 3 rolled_dice_list = roll_alchemia(roll_dice_count)
  87. return {
  88. 3 rolled_dices: rolled_dice_list,
  89. picked_dices: pick_maximum(rolled_dice_list, pick_dice_count),
  90. }
  91. end
  92. 1 def pick_maximum(dice_list, pick_dice_count)
  93. 3 then: 2 if dice_list.size <= pick_dice_count
  94. 2 dice_list
  95. else: 1 else
  96. 1 dice_list.sort.pop(pick_dice_count)
  97. end
  98. end
  99. 1 def make_roll_text(rolled_dice_list)
  100. 1 "(#{rolled_dice_list.size}D6) > #{make_dice_text(rolled_dice_list)}"
  101. end
  102. # 実際にピックできた数と要求されたピック数は一致しないケースが(ルール上)あるため、 pick_dice_count はパラメータとして受ける必要がある。
  103. 1 def make_roll_and_pick_text(rolled_dice_list, pick_dice_count, picked_dice_list)
  104. 3 "(#{rolled_dice_list.size}D6|>#{pick_dice_count}D6) > #{make_dice_text(rolled_dice_list)} >> #{make_dice_text(picked_dice_list)} > #{picked_dice_list.sum}"
  105. end
  106. 1 def make_dice_text(dice_list)
  107. 7 "[#{dice_list.sort.join ', '}]"
  108. end
  109. CATALYST_TABLES = {
  110. 1 'CElement' => DiceTable::Table.new(
  111. "奇跡の触媒(エレメント)",
  112. "1D6",
  113. [
  114. "ワンド",
  115. "水晶玉",
  116. "カード",
  117. "ステッキ",
  118. "手鏡",
  119. "宝石",
  120. ]
  121. ),
  122. 'CAlchemia' => DiceTable::Table.new(
  123. "奇跡の触媒(アルケミア)",
  124. "1D6",
  125. [
  126. "指輪",
  127. "ブレスレット",
  128. "イヤリング",
  129. "ネックレス",
  130. "ブローチ",
  131. "ヘアピン",
  132. ]
  133. ),
  134. 'CInformant' => DiceTable::Table.new(
  135. "奇跡の触媒(インフォーマント)",
  136. "1D6",
  137. [
  138. "スマートフォン",
  139. "タブレット",
  140. "ノートパソコン",
  141. "無線機(トランシーバー)",
  142. "ウェアラブルデバイス",
  143. "携帯ゲーム機",
  144. ]
  145. ),
  146. 'CInnocence' => DiceTable::Table.new(
  147. "奇跡の触媒(イノセンス)",
  148. "1D6",
  149. [
  150. "手袋",
  151. "笛",
  152. "靴",
  153. "鈴",
  154. "拡声器",
  155. "弦楽器",
  156. ]
  157. ),
  158. 'CAcquired' => DiceTable::Table.new(
  159. "奇跡の触媒(アクワイヤード)",
  160. "1D6",
  161. [
  162. "ボタン",
  163. "音声",
  164. "モーション",
  165. "脳波",
  166. "記録媒体",
  167. "AI",
  168. ]
  169. ),
  170. }.transform_keys(&:upcase).freeze
  171. ARTICLE_TABLES = {
  172. 1 'ArticleS' => DiceTable::D66Table.new(
  173. "携行品(Sサイズ)",
  174. D66SortType::ASC,
  175. {
  176. 11 => "マッチ",
  177. 12 => "ペットボトル",
  178. 13 => "試験管",
  179. 14 => "団扇",
  180. 15 => "植物",
  181. 16 => "ハンカチ",
  182. 22 => "化粧用具",
  183. 23 => "ベルト",
  184. 24 => "タバコ",
  185. 25 => "チェーン",
  186. 26 => "電池",
  187. 33 => "お菓子",
  188. 34 => "針金",
  189. 35 => "コイン",
  190. 36 => "ナイフ",
  191. 44 => "カトラリー",
  192. 45 => "砂",
  193. 46 => "スプレー",
  194. 55 => "石",
  195. 56 => "文房具",
  196. 66 => "ペンライト",
  197. }
  198. ),
  199. 'ArticleM' => DiceTable::D66ParityTable.new(
  200. "携行品(Mサイズ)",
  201. [
  202. "本",
  203. "傘",
  204. "金属板",
  205. "花火",
  206. "エアガン",
  207. "包帯",
  208. ],
  209. [
  210. "工具",
  211. "ジャケット",
  212. "ロープ",
  213. "人形",
  214. "軽食",
  215. "ガラス瓶",
  216. ]
  217. ),
  218. 'ArticleL' => DiceTable::D66ParityTable.new(
  219. "携行品(Lサイズ)",
  220. [
  221. "木刀",
  222. "釣り具",
  223. "自転車",
  224. "バット",
  225. "寝袋",
  226. "丸太",
  227. ],
  228. [
  229. "物干し竿",
  230. "鍋",
  231. "スケートボード",
  232. "シャベル(スコップ)",
  233. "タンク",
  234. "脚立",
  235. ]
  236. ),
  237. }.transform_keys(&:upcase).freeze
  238. DRAMA_SEQUENCE_TABLES = {
  239. 1 'PCInformation' => DiceTable::D66ParityTable.new(
  240. "PC情報獲得表",
  241. [
  242. "前の場面の直後 ―― 直前にやり取りをしていた場所。聞きたいことを突きつける頃合いかもしれない。",
  243. "自分の拠点 ―― 自分の心身を休められる場所。こちらのペースに引き込み、ゆさぶりをかける。",
  244. "相手の拠点 ―― 相手が生活の基点にしている場所。相手のペースに呑まれないよう、慎重にいこう。",
  245. "自学派の拠点 ―― 自分が学派の仲間と共に使用する場所。仲間に手は出させず、あくまでプレッシャーを与えるだけにしてもらう。",
  246. "カフェ、バー ―― 厳かな空気に包まれた大人の場所。ここで声を荒げるのは紳士的ではない。",
  247. "路地裏 ―― 建物と建物の間や、人通りの少ない裏通り。多少手荒な手段に出ても目立ちはしないだろう。",
  248. ],
  249. [
  250. "廃墟 ―― 廃ビル、廃工場のような人が立ち入らない場所。おあつらえ向きの場所を用意してやった。",
  251. "公共交通機関 ―― バス、電車など。昼夜問わず多くの人が利用する乗り物。敢えて人目に付く場所で詰め寄り、動揺を誘う。",
  252. "雑木林 ―― 草木が揺れる音、虫や鳥の鳴き声だけが聞こえる。そこに邪魔する者はいない。",
  253. "夜の公園 ―― 寝静まった街の公園。街灯に照らされない場所なら目立つこともないだろう。",
  254. "駐車場 ―― 立体、平面、地下を問わず車を停める場所。人の出入りの激しさに対し、そこに留まる人は少ない。目撃者も多くはないだろう。",
  255. "高架下 ―― 線路、道路の橋の下。響く騒音が自分たちの存在を薄めてくれる。",
  256. ]
  257. ),
  258. 'Reason' => DiceTable::Table.new(
  259. "理由表",
  260. "1D6",
  261. [
  262. "不信感 ―― 行動や言動になにか釈然としない部分を感じる。白黒はっきりさせよう。",
  263. "好奇心 ―― 相手のことを知りたいと掻き立てられる。知りたい気持ちを抑えられない。",
  264. "庇護感 ―― 知古の姿を重ねて守りたくなってしまう。信頼関係を君と築くため、踏み込んだところまで知っておきたい。",
  265. "嫌悪感 ―― 理由はないけど気に食わない。情報のアドバンテージを握ることで優位に立てるはずだ。",
  266. "偏愛 ―― 愛ゆえに知りたくなってしまう。君の思考、目的、感情のすべてを手に入れたい。",
  267. "直感 ―― 根拠はないが、なにか隠している気がする。一か八か、勝負に出よう。",
  268. ]
  269. ),
  270. 'Associate' => DiceTable::D66ParityTable.new(
  271. "交流表",
  272. [
  273. "前の場面の直後 ―― 直前にやり取りをした場所。ちょっと一息つくものいいだろう。",
  274. "自分の拠点 ―― 自分の心身を休められる場所。一緒にくつろぎながら話をしよう。",
  275. "相手の拠点 ―― 相手が生活の基点にしている場所。ちょっとお邪魔させてもらえないだろうか?",
  276. "相手学派の拠点 ―― 相手が学派の仲間と共に使用する場所。若干の居心地悪さはあるが、好感を持ってもらうためには我慢も必要。",
  277. "食事処 ―― ファミレス、居酒屋など。人でにぎわう食事処。気軽に飲み食いできる空間で、話も弾むはず。",
  278. "アミューズメント施設 ―― カラオケ、ボーリング、ゲームセンターなどの娯楽施設。遊べば人となりがわかる。手っ取り早くいこう。",
  279. ],
  280. [
  281. "お祭り ―― 老若男女が参加するイベント。非日常的な空気を楽しむことで、気分転換もできるだろう。",
  282. "昼間の公園 ―― 散歩する人や子連れの家族で溢れる公園。僕らにもああやって生きる道があったのだろうか。",
  283. "思い出の場所 ―― 自分にとって思い入れのある大事な場所。この人になら胸の内を明かしてもいい気分になった。",
  284. "スポーツ観戦 ―― 野球、サッカー、バスケなど。プロアマ問わず観戦する。手に汗握る展開を共に見届けよう。",
  285. "屋上 ―― 街と人を見下ろす眺めのいい場所。この景色を君は喜ぶだろうか、怖がるだろうか。",
  286. "ショッピング ―― 大型商業施設やショッピングストリートに向かう。互いの興味があるものを知るいい機会だ。",
  287. ]
  288. ),
  289. 'Contact' => DiceTable::Table.new(
  290. "接触のきっかけ表",
  291. "1D6",
  292. [
  293. "体勢を崩す ―― 転びそうになったところを支える、支えられる。",
  294. "付着物をとる ―― 髪や服についているゴミ、汚れをとってあげる。",
  295. "思わず手が出る ―― 言葉より先に、強めに手が出てしまう。",
  296. "物ごしに触れる ―― 物を渡す、拾う際に指先同士がぶつかる。",
  297. "友好のサイン ―― 肩を組む、握手をする、ハグをするなど。",
  298. "ケアをしてあげる ―― 髪をとかす、肩をもむ、頭を撫でる。相手を労ってする行為全般。",
  299. ]
  300. ),
  301. }.transform_keys(&:upcase).freeze
  302. TABLES =
  303. 1 CATALYST_TABLES.merge(ARTICLE_TABLES).merge(DRAMA_SEQUENCE_TABLES)
  304. 6 alias_catalyst_tables = CATALYST_TABLES.keys.map { |key| [key[0, 4], key] }.to_h
  305. 4 alias_article_tables = ARTICLE_TABLES.keys.map { |key| [key[0, 2] + key[-1], key] }.to_h
  306. 5 alias_drama_sequence_tables = DRAMA_SEQUENCE_TABLES.keys.map { |key| [key[0, 3], key] }.to_h
  307. 1 ALIAS = alias_catalyst_tables.merge(alias_article_tables).merge(alias_drama_sequence_tables).freeze
  308. 1 register_prefix(ALIAS.keys, TABLES.keys)
  309. end
  310. end
  311. end

lib/bcdice/game_system/Alsetto.rb

98.15% lines covered

95.24% branches covered

54 relevant lines. 53 lines covered and 1 lines missed.
21 total branches, 20 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Alsetto < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Alsetto'
  7. # ゲームシステム名
  8. 1 NAME = '詩片のアルセット'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'うたかたのあるせつと'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・成功判定:nAL[m]    ・トライアンフ無し:nALC[m]
  14. ・命中判定:nAL[m]*p   ・トライアンフ無し:nALC[m]*p
  15. ・命中判定(ガンスリンガーの根源詩):nALG[m]*p
  16. []内は省略可能。
  17. ALコマンドはトライアンフの分だけ、自動で振り足し処理を行います。
  18. 「n」でダイス数を指定。
  19. 「m」で目標値を指定。省略時は、デフォルトの「3」が使用されます。
  20. 「p」で攻撃力を指定。「*」は「x」でも可。
  21. 攻撃力指定で命中判定となり、成功数ではなく、ダメージを結果表示します。
  22. ALCコマンドはトライアンフ無しで、成功数、ダメージを結果表示します。
  23. ALGコマンドは「2以下」でトライアンフ処理を行います。
  24. 【書式例】
  25. ・5AL → 5d6で目標値3。
  26. ・5ALC → 5d6で目標値3。トライアンフ無し。
  27. ・6AL2 → 6d6で目標値2。
  28. ・4AL*5 → 4d6で目標値3、攻撃力5の命中判定。
  29. ・7AL2x10 → 7d6で目標値2、攻撃力10の命中判定。
  30. ・8ALC4x5 → 8d6で目標値4、攻撃力5、トライアンフ無しの命中判定。
  31. MESSAGETEXT
  32. 1 register_prefix('\d+AL[CG]?')
  33. 1 def initialize(command)
  34. 25 super(command)
  35. 25 @sort_add_dice = true # ダイスのソート有
  36. end
  37. 1 def eval_game_system_specific_command(command)
  38. # ALCコマンド:命中判定
  39. # ALCコマンド:成功判定
  40. 25 then: 25 else: 0 if command =~ /(\d+)AL(C|G)?(\d+)?((x|\*)(\d+))?$/i
  41. 25 rapid = Regexp.last_match(1).to_i
  42. 25 isCritical = Regexp.last_match(2).nil?
  43. 25 then: 18 if isCritical
  44. 18 criticalNumber = 1
  45. else: 7 else
  46. 7 then: 3 if Regexp.last_match(2) == "G"
  47. 3 isCritical = true
  48. 3 criticalNumber = 2
  49. else: 4 else
  50. 4 criticalNumber = 0
  51. end
  52. end
  53. 25 target = (Regexp.last_match(3) || 3).to_i
  54. 25 damage = (Regexp.last_match(6) || 0).to_i
  55. 25 return checkRoll(rapid, target, damage, isCritical, criticalNumber)
  56. end
  57. return nil
  58. end
  59. 1 def checkRoll(rapid, target, damage, isCritical, criticalNumber)
  60. 25 totalSuccessCount = 0
  61. 25 totalCriticalCount = 0
  62. 25 text = ""
  63. 25 rollCount = rapid
  64. 25 body: 37 while rollCount > 0
  65. 37 diceArray = @randomizer.roll_barabara(rollCount, 6).sort
  66. 37 diceText = diceArray.join(",")
  67. 37 successCount = 0
  68. 37 criticalCount = 0
  69. 37 diceArray.each do |i|
  70. 156 then: 66 else: 90 if i <= target
  71. 66 successCount += 1
  72. end
  73. 156 then: 20 else: 136 if i <= criticalNumber
  74. 20 criticalCount += 1
  75. end
  76. end
  77. 37 totalSuccessCount += successCount
  78. 37 else: 25 then: 12 totalCriticalCount += 1 unless criticalCount == 0
  79. 37 else: 25 then: 12 text += "+" unless text.empty?
  80. 37 text += "#{successCount}[#{diceText}]"
  81. 37 else: 33 then: 4 break unless isCritical
  82. 33 rollCount = criticalCount
  83. end
  84. 25 isDamage = (damage != 0)
  85. 25 then: 14 if isDamage
  86. 14 totalDamage = totalSuccessCount * damage
  87. 14 result = "(#{rapid}D6\<\=#{target}) > #{text} > Hits:#{totalSuccessCount}*#{damage} > #{totalDamage}ダメージ"
  88. else: 11 else
  89. 11 result = "(#{rapid}D6\<\=#{target}) > #{text} > 成功数:#{totalSuccessCount}"
  90. end
  91. 25 then: 21 else: 4 if isCritical
  92. 21 result += " / #{totalCriticalCount}トライアンフ"
  93. end
  94. 25 return result
  95. end
  96. end
  97. end
  98. end

lib/bcdice/game_system/Alshard.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/SRS'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Alshard < SRS
  6. # ゲームシステム名
  7. 1 NAME = 'アルシャード'
  8. # ゲームシステム名の読みがな
  9. 1 SORT_KEY = 'あるしやあと'
  10. # ゲームシステムの識別子
  11. 1 ID = 'Alshard'
  12. # 固有のコマンドの接頭辞を設定する
  13. 1 register_prefix('2D6', 'AL')
  14. # 成功判定のエイリアスコマンドを設定する
  15. 1 set_aliases_for_srs_roll('AL')
  16. 1 HELP_MESSAGE = help_message()
  17. end
  18. end
  19. end

lib/bcdice/game_system/AlterRaise.rb

100.0% lines covered

93.75% branches covered

99 relevant lines. 99 lines covered and 0 lines missed.
32 total branches, 30 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class AlterRaise < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'AlterRaise'
  7. # ゲームシステム名
  8. 1 NAME = 'アルトレイズ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'あるとれいす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ◆解放判定:EMA[x]
  14. [x]で達成値を指定してください。省略時はダイスロールします。
  15. 【各種表】
  16. ◆性格傾向表:PER[n]       ◆場所表:LOC[ab]
  17. ◆平穏・経験表:QUI[ab]     ◆喜び・経験表:DEL[ab]
  18. ◆心の傷・経験表:TRA[ab]    ◆シーン演出表:SCE[n]
  19. ◆スタンス表:STA[n]       ◆感情表:EMO[ab]
  20. []内のコマンドを省略でダイスロール、指定でROC結果を表示します。
  21. [n]は「1D6」、[ab]は「D66」の出目を指定してください。
  22. 【書式例】
  23. PER3:性格傾向表の「3」をROC
  24. LOC52:場所表の「52」をROC
  25. QUI:平穏・経験表をダイスロール
  26. MESSAGETEXT
  27. 1 register_prefix(
  28. 'EMA', 'PER', 'LOC', 'QUI', 'DEL',
  29. 'TRA', 'SCE', 'STA', 'EMO'
  30. )
  31. 1 def eval_game_system_specific_command(command)
  32. output =
  33. 23 else: 0 case command.upcase
  34. when: 5 when /EMA(\d+)?$/i
  35. 5 roc = (Regexp.last_match(1) || 0).to_i
  36. 5 get_emancipation_table(roc)
  37. when: 2 when /PER(\d+)?$/i
  38. 2 roc = (Regexp.last_match(1) || 0).to_i
  39. 2 get_personality_table(roc)
  40. when: 4 when /LOC(\d+)?$/i
  41. 4 roc = (Regexp.last_match(1) || 0).to_i
  42. 4 get_location_table(roc)
  43. when: 2 when /QUI(\d+)?$/i
  44. 2 roc = (Regexp.last_match(1) || 0).to_i
  45. 2 get_quiet_table(roc)
  46. when: 2 when /DEL(\d+)?$/i
  47. 2 roc = (Regexp.last_match(1) || 0).to_i
  48. 2 get_delight_table(roc)
  49. when: 2 when /TRA(\d+)?$/i
  50. 2 roc = (Regexp.last_match(1) || 0).to_i
  51. 2 get_trauma_table(roc)
  52. when: 2 when /SCE(\d+)?$/i
  53. 2 roc = (Regexp.last_match(1) || 0).to_i
  54. 2 get_scene_production_table(roc)
  55. when: 2 when /STA(\d+)?$/i
  56. 2 roc = (Regexp.last_match(1) || 0).to_i
  57. 2 get_stance_table(roc)
  58. when: 2 when /EMO(\d+)?$/i
  59. 2 roc = (Regexp.last_match(1) || 0).to_i
  60. 2 get_emotion_table(roc)
  61. end
  62. 23 return output
  63. end
  64. 1 def get_emancipation_table(roc)
  65. 5 name = "解放判定表"
  66. table = [
  67. 5 [2, '激闘。今回の端末は想定をはるかに上回る脅威だった。幾本もの太刀筋と永遠のような時間の果てに、君たちは勝利した。深手を負ったが、ギリギリ致命傷ではない。'],
  68. [4, '辛勝。今回の端末は想定以上の大物だった。刃と牙のせめぎ合いの果て、君たちは辛くも勝利した。'],
  69. [6, '勝利。今回の端末は、おおむね想定される程度の個体であった。多少の傷は負ったが、君たちは問題なく勝利できた。'],
  70. [8, '快勝。今回の端末には、危うげも無く勝利できた。君とペアのコンビネーションの賜物だろう。かすり傷を負ったが、勲章のようなものだ。'],
  71. [10, '圧勝。今回の端末は、君たちの敵ではなかった。君とペアの剣撃は瞬く間に端末を寸断し、粒子の光に還元した。'],
  72. [12, '刹那。端末をその切っ先に捉えた刹那、君たちの前で粒子の光が舞う。それ以上何も起こることはなく、世界は色を取り戻した。'],
  73. ]
  74. 5 then: 3 if roc > 1
  75. 3 dice = roc
  76. 3 then: 1 else: 2 dice = 12 if dice > 12
  77. 3 diceText = ''
  78. else: 2 else
  79. 2 dice_list = @randomizer.roll_barabara(2, 6)
  80. 2 dice = dice_list.sum()
  81. 2 diceText = "(#{dice_list.join(',')})"
  82. end
  83. 5 tableText = get_table_by_number(dice, table)
  84. # ''だと\nは文字列扱いに。
  85. 5 then: 3 else: 2 tableText += "\n【達成値7以上】GM:攻撃ルーチン1つを開示(番号はペアPLが指定) PL:戦闘開始時のアクセルレベル+1" if dice >= 7
  86. 5 return "#{name} > #{dice}#{diceText}:#{tableText}"
  87. end
  88. 1 def get_personality_table(roc)
  89. 2 name = "性格傾向表"
  90. table = [
  91. 2 [1, '挑戦'],
  92. [2, '調和'],
  93. [3, '感性'],
  94. [4, '信念'],
  95. [5, '論理'],
  96. [6, '思慮']
  97. ]
  98. 2 return get_AlterRaise_1d6_table_result(name, table, roc)
  99. end
  100. 1 def get_location_table(roc)
  101. 4 name = "場所表"
  102. table = [
  103. 4 [13, '教室'],
  104. [16, '部室'],
  105. [23, '商店街'],
  106. [26, '田舎'],
  107. [33, '都会'],
  108. [36, '駅'],
  109. [43, 'バイト'],
  110. [46, 'ステージ'],
  111. [53, '図書館'],
  112. [56, '病院'],
  113. [63, '自然'],
  114. [66, '家']
  115. ]
  116. 4 return get_AlterRaise_d66_table_result(name, table, roc)
  117. end
  118. 1 def get_quiet_table(roc)
  119. 2 name = "平穏・経験表"
  120. table = [
  121. 2 [13, '友達'],
  122. [16, '幼馴染み'],
  123. [23, '両親'],
  124. [26, '兄弟'],
  125. [33, '親戚'],
  126. [36, '理解者'],
  127. [43, '友人'],
  128. [46, '仲間'],
  129. [53, '趣味'],
  130. [56, '練習'],
  131. [63, '一人'],
  132. [66, 'お気に入り']
  133. ]
  134. 2 return get_AlterRaise_d66_table_result(name, table, roc)
  135. end
  136. 1 def get_delight_table(roc)
  137. 2 name = "喜び・経験表"
  138. table = [
  139. 2 [13, '勝利'],
  140. [16, '優勝'],
  141. [23, '出会い'],
  142. [26, '理解'],
  143. [33, '幸運'],
  144. [36, 'プレゼント'],
  145. [43, '成就'],
  146. [46, '成長'],
  147. [53, '創造'],
  148. [56, '好転'],
  149. [63, '証明'],
  150. [66, '生還']
  151. ]
  152. 2 return get_AlterRaise_d66_table_result(name, table, roc)
  153. end
  154. 1 def get_trauma_table(roc)
  155. 2 name = "心の傷・経験表"
  156. table = [
  157. 2 [13, '敗北'],
  158. [16, '仲違い'],
  159. [23, '失恋'],
  160. [26, '無理解'],
  161. [33, '無力'],
  162. [36, '孤独'],
  163. [43, '別離'],
  164. [46, '死別'],
  165. [53, '損壊'],
  166. [56, '喪失'],
  167. [63, '病'],
  168. [66, '事故']
  169. ]
  170. 2 return get_AlterRaise_d66_table_result(name, table, roc)
  171. end
  172. 1 def get_scene_production_table(roc)
  173. 2 name = "シーン演出表"
  174. table = [
  175. 2 [1, '相談。君は相手に相談したいことがあった。'],
  176. [2, '遊び。君は相手と遊びたかった。'],
  177. [3, '案内。君は自身のアリウス・パーソナルを案内したかった。'],
  178. [4, '勝負。君は相手と何らかの勝負をしたかった。'],
  179. [5, 'お願い。君は相手にお願いしたいことがあった。'],
  180. [6, '扉を開く前に。アクセルダイブ・ゲートをくぐる前に、君は相手に話したいことがあった。(*ダイブした後のシーンも演出すること)']
  181. ]
  182. 2 return get_AlterRaise_1d6_table_result(name, table, roc)
  183. end
  184. 1 def get_stance_table(roc)
  185. 2 name = "スタンス表"
  186. table = [
  187. 2 [1, '友人'],
  188. [2, '恋愛'],
  189. [3, '師事'],
  190. [4, 'ライバル'],
  191. [5, '家族'],
  192. [6, '守護']
  193. ]
  194. 2 return get_AlterRaise_1d6_table_result(name, table, roc)
  195. end
  196. 1 def get_emotion_table(roc)
  197. 2 name = "感情表"
  198. table = [
  199. 2 [13, '勇気'],
  200. [16, '怒り'],
  201. [23, '悲しみ'],
  202. [26, '喜び'],
  203. [33, '驚き'],
  204. [36, '恐れ'],
  205. [43, '安らぎ'],
  206. [46, '誠意'],
  207. [53, '庇護'],
  208. [56, '謝意'],
  209. [63, '信頼'],
  210. [66, '好意']
  211. ]
  212. 2 return get_AlterRaise_d66_table_result(name, table, roc)
  213. end
  214. 1 def get_AlterRaise_1d6_table_result(name, table, roc)
  215. 6 then: 2 if roc > 0
  216. 2 dice = roc
  217. 2 then: 1 else: 1 dice = 6 if dice > 6
  218. else: 4 else
  219. 4 dice = @randomizer.roll_once(6)
  220. end
  221. 6 tableText = get_table_by_number(dice, table)
  222. 6 return "#{name} > #{dice}:#{tableText}"
  223. end
  224. 1 def get_AlterRaise_d66_table_result(name, table, roc)
  225. 12 then: 3 if roc > 10
  226. 3 diceText = roc.to_s
  227. 3 dice1 = diceText[0, 1].to_i
  228. 3 then: 1 else: 2 dice1 = 6 if dice1 > 6
  229. 3 dice2 = diceText[1, 1].to_i
  230. 3 then: 1 else: 2 dice2 = 1 if dice2 < 1
  231. 3 else: 9 then: 1 else: 2 dice2 = 6 if dice2 > 6
  232. 9 then: 2 elsif roc > 0
  233. 2 dice1 = roc
  234. 2 then: 0 else: 2 dice1 = 6 if dice1 > 6
  235. 2 dice2 = @randomizer.roll_once(6)
  236. else: 7 else
  237. 7 dice1 = @randomizer.roll_once(6)
  238. 7 dice2 = @randomizer.roll_once(6)
  239. end
  240. 12 dice = dice1 * 10 + dice2
  241. 12 diceText = "#{dice1},#{dice2}"
  242. 12 tableText = get_table_by_number(dice, table)
  243. 12 return "#{name} > #{diceText}:#{tableText}"
  244. end
  245. end
  246. end
  247. end

lib/bcdice/game_system/Amadeus.rb

100.0% lines covered

100.0% branches covered

69 relevant lines. 69 lines covered and 0 lines missed.
20 total branches, 20 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/arithmetic_evaluator"
  3. 1 require "bcdice/format"
  4. 1 require "bcdice/normalize"
  5. 1 module BCDice
  6. 1 module GameSystem
  7. 1 class Amadeus < Base
  8. # ゲームシステムの識別子
  9. 1 ID = 'Amadeus'
  10. # ゲームシステム名
  11. 1 NAME = 'アマデウス'
  12. # ゲームシステム名の読みがな
  13. 1 SORT_KEY = 'あまてうす'
  14. # ダイスボットの使い方
  15. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  16. ・判定(Rx±y@z>=t)
  17.  能力値のダイスごとに成功・失敗の判定を行います。
  18.  x:能力ランク(S,A~D) y:修正値(省略可)
  19.  z:スペシャル最低値(省略:6) t:目標値(省略:4)
  20.   例) RA RB-1 RC>=5 RD+2 RS-1@5>=6
  21.  出力書式は
  22.   (達成値)_(判定結果)[(出目)(対応するインガ)]
  23.  C,Dランクでは対応するインガは出力されません。
  24.   出力例) 2_ファンブル![1黒] / 3_失敗[3青]
  25. ・各種表
  26.  境遇表 ECT/関係表 RT/親心表 PRT/戦場表 BST/休憩表 BT/
  27.  ファンブル表 FT/致命傷表 FWT/戦果表 BRT/ランダムアイテム表 RIT/
  28.  損傷表 WT/悪夢表 NMT/目標表 TGT/制約表 CST/
  29.  ランダムギフト表 RGT/決戦戦果表 FBT/
  30.  店内雰囲気表 SAT/特殊メニュー表 SMT
  31. ・試練表(~VT)
  32.  ギリシャ神群 GCVT/ヤマト神群 YCVT/エジプト神群 ECVT/
  33.  クトゥルフ神群 CCVT/北欧神群 NCVT/中華神群 CHVT/
  34. ラストクロニクル神群 LCVT/ケルト神群 KCVT/ダンジョン DGVT/日常 DAVT
  35. ・挑戦テーマ表(~CT)
  36.  武勇 PRCT/技術 TCCT/頭脳 INCT/霊力 PSCT/愛 LVCT/日常 DACT
  37. INFO_MESSAGE_TEXT
  38. 1 def initialize(command)
  39. 174 super(command)
  40. 174 @sort_add_dice = true
  41. 174 @enabled_d66 = true
  42. 174 @d66_sort_type = D66SortType::ASC
  43. end
  44. 1 def eval_game_system_specific_command(command)
  45. 174 roll_amadeus(command) ||
  46. roll_tables(command, self.class::TABLES)
  47. end
  48. 1 private
  49. 1 def roll_amadeus(command)
  50. 174 m = /^R([A-DS])([+\-\d]*)(@(\d))?((>=?)([+\-\d]*))?(@(\d))?$/i.match(command)
  51. 174 else: 36 then: 138 unless m
  52. 138 return nil
  53. end
  54. 36 rank = m[1]
  55. 36 modifier = ArithmeticEvaluator.eval(m[2])
  56. 36 then: 16 else: 20 cmp_op = m[6] ? Normalize.comparison_operator(m[6]) : :>=
  57. 36 then: 16 else: 20 target = m[7] ? ArithmeticEvaluator.eval(m[7]) : 4
  58. 36 special = (m[4] || m[9] || 6).to_i
  59. 36 dice_count = CHECK_DICE_COUNT[rank]
  60. 36 dice_list = @randomizer.roll_barabara(dice_count, 6)
  61. 36 dice_text = dice_list.join(",")
  62. 36 then: 28 else: 8 special_text = (special == 6 ? "" : "@#{special}")
  63. 36 then: 2 else: 34 dice_list = [dice_list.min] if rank == "D"
  64. 36 available_inga = dice_list.size > 1
  65. 36 inga_table = translate("Amadeus.inga_table")
  66. 36 success = false
  67. 36 critical = false
  68. 36 fumble = false
  69. results =
  70. 36 dice_list.map do |dice|
  71. 60 total = dice + modifier
  72. result =
  73. 60 then: 6 if dice == 1
  74. 6 fumble = true
  75. 6 else: 54 translate("Amadeus.fumble")
  76. 54 then: 12 elsif dice >= special
  77. 12 critical = true
  78. 12 success = true
  79. 12 else: 42 translate("Amadeus.special")
  80. 42 then: 22 elsif total.send(cmp_op, target)
  81. 22 success = true
  82. 22 translate("success")
  83. else: 20 else
  84. 20 translate("failure")
  85. end
  86. 60 then: 42 if available_inga
  87. 42 inga = inga_table[dice - 1]
  88. 42 "#{total}_#{result}[#{dice}#{inga}]"
  89. else: 18 else
  90. 18 "#{total}_#{result}[#{dice}]"
  91. end
  92. end
  93. sequence = [
  94. 36 "(R#{rank}#{Format.modifier(modifier)}#{special_text}#{cmp_op}#{target})",
  95. "[#{dice_text}]#{Format.modifier(modifier)}",
  96. results.join(" / ")
  97. ]
  98. 36 Result.new.tap do |r|
  99. 36 r.text = sequence.join(" > ")
  100. 36 then: 28 if success
  101. 28 r.success = true
  102. 28 r.critical = critical
  103. else: 8 else
  104. 8 r.failure = true
  105. 8 r.fumble = fumble
  106. end
  107. end
  108. end
  109. 1 CHECK_DICE_COUNT = {"S" => 4, "A" => 3, "B" => 2, "C" => 1, "D" => 2}.freeze
  110. 1 class << self
  111. 1 private
  112. 1 def translate_tables(locale)
  113. {
  114. 2 "ECT" => DiceTable::Table.from_i18n("Amadeus.table.ECT", locale),
  115. "BST" => DiceTable::Table.from_i18n("Amadeus.table.BST", locale),
  116. "RT" => DiceTable::Table.from_i18n("Amadeus.table.RT", locale),
  117. "PRT" => DiceTable::Table.from_i18n("Amadeus.table.PRT", locale),
  118. "FT" => DiceTable::Table.from_i18n("Amadeus.table.FT", locale),
  119. "BT" => DiceTable::D66Table.from_i18n("Amadeus.table.BT", locale),
  120. "FWT" => DiceTable::Table.from_i18n("Amadeus.table.FWT", locale),
  121. "BRT" => DiceTable::Table.from_i18n("Amadeus.table.BRT", locale),
  122. "RIT" => DiceTable::Table.from_i18n("Amadeus.table.RIT", locale),
  123. "WT" => DiceTable::Table.from_i18n("Amadeus.table.WT", locale),
  124. "NMT" => DiceTable::Table.from_i18n("Amadeus.table.NMT", locale),
  125. "TGT" => DiceTable::Table.from_i18n("Amadeus.table.TGT", locale),
  126. "CST" => DiceTable::Table.from_i18n("Amadeus.table.CST", locale),
  127. "GCVT" => DiceTable::Table.from_i18n("Amadeus.table.GCVT", locale),
  128. "YCVT" => DiceTable::Table.from_i18n("Amadeus.table.YCVT", locale),
  129. "ECVT" => DiceTable::Table.from_i18n("Amadeus.table.ECVT", locale),
  130. "CCVT" => DiceTable::Table.from_i18n("Amadeus.table.CCVT", locale),
  131. "NCVT" => DiceTable::Table.from_i18n("Amadeus.table.NCVT", locale),
  132. "DGVT" => DiceTable::Table.from_i18n("Amadeus.table.DGVT", locale),
  133. "DAVT" => DiceTable::Table.from_i18n("Amadeus.table.DAVT", locale),
  134. "PRCT" => DiceTable::Table.from_i18n("Amadeus.table.PRCT", locale),
  135. "TCCT" => DiceTable::Table.from_i18n("Amadeus.table.TCCT", locale),
  136. "INCT" => DiceTable::Table.from_i18n("Amadeus.table.INCT", locale),
  137. "PSCT" => DiceTable::Table.from_i18n("Amadeus.table.PSCT", locale),
  138. "LVCT" => DiceTable::Table.from_i18n("Amadeus.table.LVCT", locale),
  139. "DACT" => DiceTable::Table.from_i18n("Amadeus.table.DACT", locale),
  140. "RGT" => DiceTable::Table.from_i18n("Amadeus.table.RGT", locale),
  141. "FBT" => DiceTable::Table.from_i18n("Amadeus.table.FBT", locale),
  142. "CHVT" => DiceTable::Table.from_i18n("Amadeus.table.CHVT", locale),
  143. "LCVT" => DiceTable::Table.from_i18n("Amadeus.table.LCVT", locale),
  144. "KCVT" => DiceTable::Table.from_i18n("Amadeus.table.KCVT", locale),
  145. "SAT" => DiceTable::D66Table.from_i18n("Amadeus.table.SAT", locale),
  146. "SMT" => DiceTable::D66Table.from_i18n("Amadeus.table.SMT", locale),
  147. }
  148. end
  149. end
  150. 1 TABLES = translate_tables(:ja_jp)
  151. 1 register_prefix('R[A-DS]', TABLES.keys)
  152. end
  153. end
  154. end

lib/bcdice/game_system/Amadeus_Korean.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/Amadeus"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Amadeus_Korean < Amadeus
  6. # ゲームシステムの識別子
  7. 1 ID = 'Amadeus:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '아마데우스'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:아마데우스'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・판정(Rx±y@z>=t)
  15.  다이스별로 성공, 실패의 판정을 합니다.
  16.  x:x에 랭크(S,A~D)를 입력.
  17.  y:y에 수정치를 입력. ±의 계산에 대응. 생략가능.
  18.  z:z에 스페셜이 되는 주사위 눈의 최저치를 입력.
  19.  생략한 경우, 6의 값만 스페셜이 됩니다.
  20.  t:t에 목표치를 입력. ±의 계산에 대응. 생략가능.
  21.  목표치를 생략한 경우, 목표치는 4로 계산됩니다.
  22.  예) RA RB-1 RC>=5 RD+2 RS-1@5>=6
  23.  ※ RB++ 나 RA- 같은, 플러스 마이너스만의 표기로는 계산되지 않습니다.
  24.  "달성치"_"판정결과"["주사위 눈""대응하는 인과"]와 같이 출력됩니다.
  25.  단, C.D랭크에서는 대응하는 인과가 출력되지 않습니다.
  26.  출력예) 1_펌블![1흑] / 3_실패[3청]
  27. ・각종표
  28.   조우표 ECT/관계표 RT/부모마음표 PRT/전장표 BST/휴식표 BT/
  29.   펌블표 FT/치명상표 FWT/전과표 BRT/랜덤아이템표 RIT/
  30.   손상표 WT/악몽표 NMT/목표표 TGT/制約表 CST/
  31.   ランダムギフト表 RGT/決戦戦果表 FBT/
  32.   店内雰囲気表 SAT/特殊メニュー表 SMT
  33. ・試練表(~VT)
  34.  ギリシャ神群 GCVT/ヤマト神群 YCVT/エジプト神群 ECVT/
  35.  クトゥルフ神群 CCVT/北欧神群 NCVT/中華神群 CHVT/
  36. ラストクロニクル神群 LCVT/ケルト神群 KCVT/ダンジョン DGVT/日常 DAVT
  37. ・挑戦テーマ表(~CT)
  38.  武勇 PRCT/技術 TCCT/頭脳 INCT/霊力 PSCT/愛 LVCT/日常 DACT
  39. INFO_MESSAGE_TEXT
  40. 1 def initialize(command)
  41. 87 super(command)
  42. 87 @locale = :ko_kr
  43. end
  44. 1 register_prefix_from_super_class()
  45. 1 TABLES = translate_tables(:ko_kr)
  46. end
  47. end
  48. end

lib/bcdice/game_system/AngelGear.rb

100.0% lines covered

100.0% branches covered

34 relevant lines. 34 lines covered and 0 lines missed.
14 total branches, 14 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/dice_table/table"
  3. 1 require "bcdice/dice_table/d66_grid_table"
  4. 1 require "bcdice/arithmetic"
  5. 1 module BCDice
  6. 1 module GameSystem
  7. 1 class AngelGear < Base
  8. # ゲームシステムの識別子
  9. 1 ID = 'AngelGear'
  10. # ゲームシステム名
  11. 1 NAME = 'エンゼルギア 天使大戦TRPG The 2nd Editon'
  12. # ゲームシステム名の読みがな
  13. 1 SORT_KEY = 'えんせるきあ2'
  14. # ダイスボットの使い方
  15. 1 HELP_MESSAGE = <<~MESSAGETEXT
  16. ・判定 nAG[s][±a]
  17. []内は省略可能。
  18. n:判定値
  19. s:技能値
  20. a:修正
  21. (例)
  22. 12AG 10AG3±20
  23. ・感情表 ET
  24. MESSAGETEXT
  25. 1 def initialize(command)
  26. 12 super(command)
  27. 12 @sort_barabara_dice = true # バラバラロール(Bコマンド)でソート有
  28. end
  29. 1 def eval_game_system_specific_command(command)
  30. 12 then: 9 if (m = /^(\d+)AG(\d+)?(([+-]\d+)*)$/.match(command))
  31. 9 then: 8 else: 1 resolute_action(m[1].to_i, m[2]&.to_i, m[3], command)
  32. else: 3 else
  33. 3 roll_tables(command, TABLES)
  34. end
  35. end
  36. 1 def resolute_action(num_dice, skill_value, modify, command)
  37. 9 dice = @randomizer.roll_barabara(num_dice, 6).sort
  38. 9 dice_text = dice.join(",")
  39. 9 modify_n = 0
  40. 9 success = 0
  41. 9 then: 8 else: 1 if skill_value
  42. 88 success = dice.count { |val| val <= skill_value }
  43. 8 else: 3 then: 5 modify_n = Arithmetic.eval(modify, RoundType::FLOOR) unless modify.empty?
  44. end
  45. 9 then: 2 else: 7 gospel = '(福音発生)' if success + modify_n >= 100
  46. 9 output = "(#{command}) > #{success}[#{dice_text}]#{format('%+d', modify_n)} > 成功数: #{success + modify_n}#{gospel}"
  47. 9 then: 2 if success + modify_n >= 100
  48. 2 else: 7 Result.critical(output)
  49. 7 then: 5 elsif 0 < success + modify_n
  50. 5 Result.success(output)
  51. else: 2 else
  52. 2 Result.failure(output)
  53. end
  54. end
  55. TABLES = {
  56. 1 'ET' => DiceTable::D66GridTable.new(
  57. '感情表',
  58. [
  59. [
  60. '好奇心(好奇心)',
  61. '憧れ(あこがれ)',
  62. '尊敬(そんけい)',
  63. '仲間意識(なかまいしき)',
  64. '母性愛(ぼせいあい)',
  65. '感心(かんしん)'
  66. ],
  67. [
  68. '純愛(じゅんあい)',
  69. '友情(ゆうじょう)',
  70. '同情(どうじょう)',
  71. '父性愛(ふせいあい)',
  72. '幸福感(こうふくかん)',
  73. '信頼(しんらい)'
  74. ],
  75. [
  76. '競争心(きょうそうしん)',
  77. '親近感(しんきんかん)',
  78. 'まごころ',
  79. '好意(こうい)',
  80. '有為(ゆうい)',
  81. '崇拝(すうはい)'
  82. ],
  83. [
  84. '大嫌い(だいきらい)',
  85. '妬み(ねたみ)',
  86. '侮蔑(ぶべつ)',
  87. '腐れ縁(くされえん)',
  88. '恐怖(きょうふ)',
  89. '劣等感(れっとうかん)'
  90. ],
  91. [
  92. '偏愛(へんあい)',
  93. '寂しさ(さびしさ)',
  94. '憐憫(れんびん)',
  95. '闘争心(とうそうしん)',
  96. '食傷(しょくしょう)',
  97. '嘘つき(うそつき)'
  98. ],
  99. [
  100. '甘え(あまえ)',
  101. '苛立ち(いらだち)',
  102. '下心(したごころ)',
  103. '憎悪(ぞうお)',
  104. '疑惑(ぎわく)',
  105. '支配(しはい)'
  106. ],
  107. ]
  108. )
  109. }.freeze
  110. 1 register_prefix('\d+AG', TABLES.keys)
  111. end
  112. end
  113. end

lib/bcdice/game_system/AniMalus.rb

99.23% lines covered

93.48% branches covered

130 relevant lines. 129 lines covered and 1 lines missed.
46 total branches, 43 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class AniMalus < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'AniMalus'
  7. # ゲームシステム名
  8. 1 NAME = 'アニマラス'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'あにまらす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGETEXT
  13. ■ステータスのダイス判定 n[+-b]AM<=t,x n:能力値 b:修正値(省略可能) t:成功値 x:必要成功数
  14. 例)3AM<=2,1: ダイスを3個振って、成功値2,必要成功数1で判定。その結果(成功数,成功・失敗,クリティカル,ファンブル)を表示
  15. ■探索技能のダイス判定 [+-b]AI<=t,x t:探索技能レベル b:修正値(省略可能) x:必要成功数
  16. 例)AI<=3,1: ダイスを3個振って、探索技能レベル3,必要成功数1で判定。その結果(成功数,成功・失敗,クリティカル,ファンブル)を表示
  17. ■攻撃判定 [+-b]AA<=t t:戦闘技能レベル b:修正値(省略可能)
  18. 例)AA<=3: ダイスを3個振って、戦闘技能レベル3で判定。その結果(成功・失敗,ダメージ,クリティカル,ファンブル)を表示
  19. ■防御判定 [+-b]AG=t t:攻撃技能レベル b:修正値(省略可能)
  20. 例)AG=2: ダイスを3個振って、攻撃技能レベル2で判定。その結果(成功・失敗,ダメージ軽減,クリティカル,ファンブル)を表示
  21. ■回避判定 [+-b]AD=t t:攻撃技能レベル b:修正値(省略可能)
  22. 例)AD=3: ダイスを1個振って、攻撃技能レベル3で判定。その結果(成功・失敗)を表示
  23. INFO_MESSAGETEXT
  24. 1 register_prefix('[-+\d]*A[MIAGD]')
  25. 1 def initialize(command)
  26. 31 super(command)
  27. 31 @sort_barabara_dice = true # バラバラロール(Bコマンド)でソート有
  28. end
  29. 1 def eval_game_system_specific_command(command)
  30. 31 resolute_action(command) ||
  31. resolute_investigation(command) ||
  32. resolute_attacking(command) ||
  33. resolute_guarding(command) ||
  34. resolute_dodging(command)
  35. end
  36. 1 private
  37. 1 def with_symbol(number)
  38. 31 then: 21 if number == 0
  39. 21 else: 10 return ""
  40. 10 then: 10 elsif number > 0
  41. 10 return "+#{number}"
  42. else: 0 else
  43. return number.to_s
  44. end
  45. end
  46. # ステータスの判定
  47. # @param [String] command
  48. # @return [Result]
  49. 1 def resolute_action(command)
  50. 31 m = /^(\d+)([-+]\d+)?AM<=(\d+),(\d)$/.match(command)
  51. 31 else: 6 then: 25 return nil unless m
  52. 6 num_dice = m[1].to_i
  53. 6 num_bonus = m[2].to_i
  54. 6 num_target = m[3].to_i
  55. 6 num_success = m[4].to_i
  56. 6 dice = @randomizer.roll_barabara(num_dice + num_bonus, 6).sort
  57. 6 dice_text = dice.join(",")
  58. 28 success_num = dice.count { |val| val <= num_target }
  59. 6 is_critical = dice.include?(1) && dice.include?(2) && dice.include?(3)
  60. 6 is_fumble = dice.include?(4) && dice.include?(5) && dice.include?(6)
  61. 6 return Result.new.tap do |result|
  62. 6 result.critical = is_critical
  63. 6 result.fumble = is_fumble
  64. 6 result.condition = (success_num >= num_success)
  65. sequence = [
  66. 6 "(#{num_dice}#{with_symbol(num_bonus)}AM<=#{num_target},#{num_success})",
  67. dice_text,
  68. "成功数#{success_num}",
  69. 6 then: 3 if result.success?
  70. 3 "成功"
  71. else: 3 else
  72. 3 "失敗"
  73. end
  74. ].compact
  75. 6 then: 2 else: 4 sequence.push("クリティカル") if result.critical?
  76. 6 then: 2 else: 4 sequence.push("ファンブル") if result.fumble?
  77. 6 result.text = sequence.join(" > ")
  78. end
  79. end
  80. # 探索技能の判定
  81. # @param [String] command
  82. # @return [Result]
  83. 1 def resolute_investigation(command)
  84. 25 m = /^([-+]\d+)?AI<=(\d+),(\d)$/.match(command)
  85. 25 else: 6 then: 19 return nil unless m
  86. 6 num_bonus = m[1].to_i
  87. 6 num_target = m[2].to_i
  88. 6 num_success = m[3].to_i
  89. 6 dice = @randomizer.roll_barabara(3 + num_bonus, 6).sort
  90. 6 dice_text = dice.join(",")
  91. 28 success_num = dice.count { |val| val <= num_target }
  92. 6 is_critical = dice.include?(1) && dice.include?(2) && dice.include?(3)
  93. 6 is_fumble = dice.include?(4) && dice.include?(5) && dice.include?(6)
  94. 6 return Result.new.tap do |result|
  95. 6 result.critical = is_critical
  96. 6 result.fumble = is_fumble
  97. 6 result.condition = (success_num >= num_success)
  98. sequence = [
  99. 6 "(#{with_symbol(num_bonus)}AI<=#{num_target},#{num_success})",
  100. dice_text,
  101. "成功数#{success_num}",
  102. 6 then: 3 if result.success?
  103. 3 "成功"
  104. else: 3 else
  105. 3 "失敗"
  106. end
  107. ].compact
  108. 6 then: 2 else: 4 sequence.push("クリティカル") if result.critical?
  109. 6 then: 2 else: 4 sequence.push("ファンブル") if result.fumble?
  110. 6 result.text = sequence.join(" > ")
  111. end
  112. end
  113. # 攻撃技能の判定
  114. # @param [String] command
  115. # @return [Result]
  116. 1 def resolute_attacking(command)
  117. 19 m = /^([-+]\d+)?AA<=(\d+)$/.match(command)
  118. 19 else: 10 then: 9 return nil unless m
  119. 10 num_bonus = m[1].to_i
  120. 10 num_target = m[2].to_i
  121. 10 dice = @randomizer.roll_barabara(3 + num_bonus, 6).sort
  122. 10 dice_text = dice.join(",")
  123. 45 success_num = dice.count { |val| val <= num_target }
  124. 10 is_critical = dice.include?(1) && dice.include?(2) && dice.include?(3)
  125. 10 is_fumble = dice.include?(4) && dice.include?(5) && dice.include?(6)
  126. 10 damage1 = dice.max
  127. 10 damage2 = dice.max
  128. 10 (1..num_target).each do |idx|
  129. 30 then: 5 else: 25 if dice.count(idx) > 1
  130. 5 now_damage = damage1 + 3 * (dice.count(idx) - 1)
  131. 5 then: 5 else: 0 damage2 = now_damage if damage2 < now_damage
  132. end
  133. end
  134. 10 return Result.new.tap do |result|
  135. 10 result.critical = is_critical
  136. 10 result.fumble = is_fumble
  137. 10 result.condition = (success_num > 0)
  138. sequence = [
  139. 10 "(#{with_symbol(num_bonus)}AA<=#{num_target})",
  140. dice_text,
  141. "成功数#{success_num}",
  142. 10 then: 8 if result.success?
  143. 8 "成功"
  144. else: 2 else
  145. 2 "失敗"
  146. end
  147. ].compact
  148. 10 then: 8 else: 2 if result.success?
  149. 8 sequence.push("最大ダメージ(#{damage2})")
  150. end
  151. 10 then: 2 else: 8 sequence.push("クリティカル") if result.critical?
  152. 10 then: 2 else: 8 sequence.push("ファンブル") if result.fumble?
  153. 10 result.text = sequence.join(" > ")
  154. end
  155. end
  156. # 防御技能の判定
  157. # @param [String] command
  158. # @return [Result]
  159. 1 def resolute_guarding(command)
  160. 9 m = /^([-+]\d+)?AG=(\d+)$/.match(command)
  161. 9 else: 6 then: 3 return nil unless m
  162. 6 num_bonus = m[1].to_i
  163. 6 num_target = m[2].to_i
  164. 6 dice = @randomizer.roll_barabara(3 + num_bonus, 6).sort
  165. 6 dice_text = dice.join(",")
  166. 6 success_num = dice.count(num_target)
  167. 6 is_critical = dice.include?(1) && dice.include?(2) && dice.include?(3)
  168. 6 is_fumble = dice.include?(4) && dice.include?(5) && dice.include?(6)
  169. 6 return Result.new.tap do |result|
  170. 6 result.critical = is_critical
  171. 6 result.fumble = is_fumble
  172. 6 result.condition = (success_num > 0)
  173. sequence = [
  174. 6 "(#{with_symbol(num_bonus)}AG=#{num_target})",
  175. dice_text,
  176. "成功数#{success_num}",
  177. 6 then: 4 if result.success?
  178. 4 "成功 > ダメージ軽減(#{success_num * 2})"
  179. else: 2 else
  180. 2 "失敗"
  181. end
  182. ].compact
  183. 6 then: 3 else: 3 sequence.push("クリティカル") if result.critical?
  184. 6 then: 2 else: 4 sequence.push("ファンブル") if result.fumble?
  185. 6 result.text = sequence.join(" > ")
  186. end
  187. end
  188. # 回避技能の判定
  189. # @param [String] command
  190. # @return [Result]
  191. 1 def resolute_dodging(command)
  192. 3 m = /^([-+]\d+)?AD=(\d+)$/.match(command)
  193. 3 else: 3 then: 0 return nil unless m
  194. 3 num_bonus = m[1].to_i
  195. 3 num_target = m[2].to_i
  196. 3 dice = @randomizer.roll_barabara(1 + num_bonus, 6)
  197. 3 dice_text = dice.join(",")
  198. 3 success_num = dice.count(num_target)
  199. 3 return Result.new.tap do |result|
  200. 3 result.condition = (success_num > 0)
  201. sequence = [
  202. 3 "(#{with_symbol(num_bonus)}AD=#{num_target})",
  203. dice_text,
  204. "成功数#{success_num}",
  205. 3 then: 2 if result.success?
  206. 2 "成功(ダメージ無効)"
  207. else: 1 else
  208. 1 "失敗"
  209. end
  210. ].compact
  211. 3 result.text = sequence.join(" > ")
  212. end
  213. end
  214. end
  215. end
  216. end

lib/bcdice/game_system/AnimaAnimus.rb

97.06% lines covered

90.0% branches covered

34 relevant lines. 33 lines covered and 1 lines missed.
10 total branches, 9 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/dice_table/table'
  3. 1 require 'bcdice/dice_table/range_table'
  4. 1 require 'bcdice/arithmetic'
  5. 1 module BCDice
  6. 1 module GameSystem
  7. 1 class AnimaAnimus < Base
  8. # ゲームシステムの識別子
  9. 1 ID = 'AnimaAnimus'
  10. # ゲームシステム名
  11. 1 NAME = 'アニマアニムス'
  12. # ゲームシステム名の読みがな
  13. #
  14. # 「ゲームシステム名の読みがなの設定方法」(docs/dicebot_sort_key.md)を参考にして
  15. # 設定してください
  16. 1 SORT_KEY = 'あにまあにむす'
  17. # ダイスボットの使い方
  18. 1 HELP_MESSAGE = <<~MESSAGETEXT
  19. ・行為判定(xAN<=y±z)
  20.  十面ダイスをx個振って判定します。達成値が算出されます(クリティカル発生時は2増加)。
  21.  x:振るダイスの数。魂魄値や攻撃値。
  22.  y:成功値。
  23.  z:成功値への補正。省略可能。
  24.  (例) 2AN<=3+1 5AN<=7
  25. ・各種表
  26.  情報収集表 IGT/喪失表 LT
  27. MESSAGETEXT
  28. 1 def eval_game_system_specific_command(command)
  29. 23 m = /(\d+)AN<=(\d+([+-]\d+)*)/i.match(command)
  30. 23 then: 4 if TABLES.key?(command)
  31. 4 else: 19 return roll_tables(command, TABLES)
  32. 19 then: 19 elsif m
  33. 19 return check_action(m)
  34. else: 0 else
  35. return nil
  36. end
  37. end
  38. 1 def check_action(match_data)
  39. 19 dice_cnt = Arithmetic.eval(match_data[1], RoundType::FLOOR)
  40. 19 target = Arithmetic.eval(match_data[2], RoundType::FLOOR)
  41. 19 debug("dice_cnt", dice_cnt)
  42. 19 debug("target", target)
  43. 19 dice_arr = @randomizer.roll_barabara(dice_cnt, 10)
  44. 19 dice_str = dice_arr.join(",")
  45. 94 suc_cnt = dice_arr.count { |x| x <= target }
  46. 19 has_critical = dice_arr.include?(1)
  47. 19 then: 7 else: 12 result = has_critical ? suc_cnt + 2 : suc_cnt
  48. 19 Result.new.tap do |r|
  49. 19 then: 16 else: 3 then: 7 else: 12 r.text = "(#{dice_cnt}B10<=#{target}) > #{dice_str} > #{result > 0 ? '成功' : '失敗'}(達成値:#{result})#{has_critical ? ' (クリティカル発生)' : ''}"
  50. 19 r.critical = has_critical
  51. 19 r.success = result > 0
  52. 19 r.failure = !r.success?
  53. end
  54. end
  55. TABLES = {
  56. 1 'IGT' => DiceTable::Table.new(
  57. '情報収集表',
  58. '1d10',
  59. [
  60. 'ストリートファイト/<格闘>/「俺に勝てたら教えてやるよ」情報を知る魂願者から勝負を挑まれた。生き延びるためにもこの勝負、負けるわけにはいかない。',
  61. '追跡!/<追跡/逃走>/有益な情報を持っている人間を見つけたが、こちらの顔を見るなり逃げ出した。どうにかして捕まえなくてはならない。',
  62. '脅し/<威圧>/ならず者たちが集まるバーにやってきた。裏社会に生きる彼らを脅せば有益な情報が手に入るはずだ。',
  63. 'インターネット/<コンピュータ>/SNSやニュースなど、インターネット上の情報を調査する。デマには騙されないようにしなくては。',
  64. '瀕死の情報提供者/<医学>/情報を知る人物がいると聞いてやってきたら、その人物が瀕死の重傷を負っていた。なんとかして蘇生させなくては。',
  65. '潜入捜査/<隠密>/敵対する魂願者たちのグループに潜り込んでの調査活動。リスクは高いが、有益な情報が手に入る確率は高い。',
  66. '情報交換/<交渉>/友好的な関係にある魂願者との情報交換。うまく話を聞き出すことができるとよいが。',
  67. '魔宴の情報屋/<調達>/魔宴の情報屋に接触して情報を聞き出すことにした。一筋縄ではいかない相手らしいが、はたして……?',
  68. '違法調査/<犯罪>/法に触れるやり方で情報を集めることにした。ハッキング、窃盗、恐喝、どんな手段を選ぼうか。',
  69. '聞き込み/<自我>/街ゆく人びとに聞き込みを行なう。地道な活動こそが目標にたどり着くための最短の方法だ。',
  70. ]
  71. ),
  72. 'LT' => DiceTable::RangeTable.new(
  73. '喪失表',
  74. '1d10',
  75. [
  76. [1..2, "存在/存在が希薄になり、知り合いや友人に自分の存在を忘れられてしまう。いずれ大切なパートナーの記憶からも消え、この世界でひとりぼっちになる。\nあなたの出自を消去すること。"],
  77. [3..4, "記憶/自分の大切な記憶をひとつ失なう。これからは力を使うたびに記憶をひとつ失なうことになり、最後には大切なパートナーのことも思い出せなくなってしまう。\nあなたのメモリアをひとつ選択して消去すること。シナリオメモリアは選択できない。"],
  78. [5..6, "容姿/だんだんと以前とはかけ離れた姿に変わっていく。いずれ誰も自分のことを自分だと気づかなくなるのだろう。\nあなたの特徴的な外見を失なう。内容をふさわしいものに書き換えること(特徴的な外見が美しい髪であれば醜い髪など)。"],
  79. [7..8, "感情/喜怒哀楽の感情のうち、いずれかひとつを失なう。力を使うたびに他の感情も失っていき、最後にはただ生き残るために戦う機械となる。\nポジティブかネガティブのどちらかを選択する。選択した感情をすべてのメモリアから消去する。消去した結果、表出感情がなくなってしまった場合、残った感情を表出感情にすること。なお、新しくメモリアを取得した場合も、選んだ感情を得ることはできない。"],
  80. [9..10, "五感/少しずつ五感が鈍くなる。今までできていたはずのことができなくなってしまう。\nあなたの特技をひとつ選択する。選択した特技に×をつけること。×が付いた技能で判定を行なうことはできず、判定を求められた場合は自動的に失敗となる。"],
  81. ]
  82. ),
  83. }.freeze
  84. # ダイスボットで使用するコマンドを配列で列挙する
  85. 1 register_prefix('\d+AN<=', TABLES.keys)
  86. end
  87. end
  88. end

lib/bcdice/game_system/Aoharubaan.rb

100.0% lines covered

100.0% branches covered

44 relevant lines. 44 lines covered and 0 lines missed.
14 total branches, 14 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Aoharubaan < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Aoharubaan'
  7. # ゲームシステム名
  8. 1 NAME = 'あおはるばーんっ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'あおはるはあんつ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~HELP
  13. カレカノ反応表( KR, KReaction )
  14. HELP
  15. 1 JUDGE_ROLL_REG = /^(1d6?|d6)(\+\d+)?(>=|=>)(\d+)$/i.freeze
  16. 1 register_prefix('(1d6?|d6)(\+\d+)?(>=|=>)(\d+)')
  17. 1 def eval_game_system_specific_command(command)
  18. 13 command = ALIAS[command] || command
  19. 13 then: 9 if (m = JUDGE_ROLL_REG.match(command))
  20. 9 roll_judge(m[2], m[4])
  21. else: 4 else
  22. 4 roll_tables(command, TABLES)
  23. end
  24. end
  25. 1 private
  26. 1 def roll_judge(modifier_expression, border_expression)
  27. 9 then: 4 else: 5 modifier = modifier_expression ? Arithmetic.eval(modifier_expression, RoundType::FLOOR) : nil
  28. 9 border = border_expression.to_i
  29. 9 command_text = make_command_text(modifier, border)
  30. 9 dice = @randomizer.roll_once(6)
  31. 9 score = dice + modifier.to_i
  32. 9 is_success = score >= border # 「成功」か?
  33. 9 is_right = is_success && score == border # 「ピタリ賞」か?
  34. 9 is_excellent = is_success && score >= 7 # 「限界突破」か?
  35. 9 result_elements = []
  36. 9 then: 7 else: 2 result_elements << (is_success ? '成功' : '失敗')
  37. 9 then: 2 else: 7 result_elements << "ピタリ賞" if is_right
  38. 9 then: 2 else: 7 result_elements << "限界突破" if is_excellent
  39. 9 message_elements = []
  40. 9 message_elements << command_text
  41. 9 then: 4 else: 5 message_elements << "#{dice}+#{modifier}" if modifier
  42. 9 message_elements << score
  43. 9 message_elements << result_elements.join(" & ")
  44. 9 Result.new(message_elements.join(' > ')).tap do |r|
  45. 9 r.condition = is_success
  46. 9 r.critical = is_right || is_excellent
  47. end
  48. end
  49. 1 def make_command_text(modifier, border)
  50. 9 command = "1D6"
  51. 9 then: 4 else: 5 command = "#{command}+#{modifier}" if modifier
  52. 9 command = "#{command}>=#{border}"
  53. 9 "(#{command})"
  54. end
  55. 1 ALIAS = {
  56. "KR" => "KReaction",
  57. }.transform_keys(&:upcase).transform_values(&:upcase).freeze
  58. TABLES = {
  59. 1 "KReaction" => DiceTable::RangeTable.new(
  60. "カレカノ反応表",
  61. "1D6",
  62. [
  63. [1..2, "何となく素っ気ない気がする。"],
  64. [3..4, "いつもと変わらない安心感。"],
  65. [5..6, "何故だかすごくデレてきた! 嬉しくて〈テンション〉1回復。"],
  66. ]
  67. ),
  68. }.transform_keys(&:upcase).freeze
  69. 1 register_prefix(ALIAS.keys, TABLES.keys)
  70. end
  71. end
  72. end

lib/bcdice/game_system/Arianrhod.rb

100.0% lines covered

100.0% branches covered

22 relevant lines. 22 lines covered and 0 lines missed.
8 total branches, 8 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Arianrhod < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Arianrhod'
  7. # ゲームシステム名
  8. 1 NAME = 'アリアンロッドRPG'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ありあんろつとRPG'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・クリティカル、ファンブルの自動判定を行います。(クリティカル時の追加ダメージも表示されます)
  14. ・D66ダイスあり
  15. INFO_MESSAGE_TEXT
  16. 1 def initialize(command)
  17. 54 super(command)
  18. 54 @sort_add_dice = true
  19. 54 @d66_sort_type = D66SortType::NO_SORT
  20. end
  21. 1 def result_nd6(total, _dice_total, dice_list, cmp_op, target)
  22. 36 n_max = dice_list.count(6)
  23. 36 if dice_list.count(1) == dice_list.size
  24. then: 8 # 全部1の目ならファンブル
  25. 8 else: 28 Result.fumble(translate("fumble"))
  26. 28 elsif n_max >= 2
  27. then: 10 # 2個以上6の目があったらクリティカル
  28. 10 else: 18 Result.critical(translate("Arianrhod.critical", dice: n_max))
  29. 18 then: 2 elsif cmp_op != :>= || target == '?'
  30. 2 else: 16 nil
  31. 16 then: 8 elsif total >= target
  32. 8 Result.success(translate("success"))
  33. else: 8 else
  34. 8 Result.failure(translate("failure"))
  35. end
  36. end
  37. end
  38. end
  39. end

lib/bcdice/game_system/Arianrhod_Korean.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/Arianrhod"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Arianrhod_Korean < Arianrhod
  6. # ゲームシステムの識別子
  7. 1 ID = 'Arianrhod:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '아리안로드RPG'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:아리안로드RPG'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・크리티컬, 펌블의 자동판정을 행합니다.(크리티컬 시의 추가 대미지도 표시됩니다)
  15. ・D66 다이스 있음
  16. INFO_MESSAGE_TEXT
  17. 1 def initialize(command)
  18. 27 super(command)
  19. 27 @locale = :ko_kr
  20. end
  21. 1 register_prefix_from_super_class()
  22. end
  23. end
  24. end

lib/bcdice/game_system/ArknightsFan.rb

99.41% lines covered

92.0% branches covered

170 relevant lines. 169 lines covered and 1 lines missed.
75 total branches, 69 branches covered and 6 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class ArknightsFan < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "ArknightsFan"
  7. # ゲームシステム名
  8. 1 NAME = "アークナイツTRPG by daaaper"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "ああくないつTRPGはいてえはあ"
  11. 1 HELP_MESSAGE = <<~TEXT
  12. ■ 能力値判定 (nADm<=x)
  13. nDmのダイスロールをして、出目が x 以下であれば成功。
  14. 出目が91以上でエラー。
  15. 出目が10以下でクリティカル。
  16. ■ 攻撃/防御判定 (nABm<=x)
  17. nBmのダイスロールをして、
  18. 出目が x 以下であれば成功数+1。
  19. 出目が91以上でエラー。成功数-1。
  20. 出目が10以下でクリティカル。成功数+1。
  21. 上記による成功数をカウント。
  22. ■ 役職効果付き攻撃判定 (nABm<=x--役職名h)
  23. h: 健康状態(0: 健康、1: 中等症、2: 重症)
  24. nBmのダイスロールをして、
  25. 出目が x 以下であれば成功数+1。
  26. 出目が91以上でエラー。成功数-1。
  27. 出目が10以下でクリティカル。成功数+1。
  28. 上記による成功数をカウントした上で、以下の役職名による成功数増加効果を適応。
  29. 狙撃(SNI): 健康(h=0)かつ成功数1以上のとき、成功数+1。
  30. 健康状態hを省略した場合、健康(h=0)として扱われる。
  31. ■ 鉱石病判定 (ORPx@y+Dd+Tt)
  32. x: 生理的耐性、y: 上昇後侵食度、d: ダイス補正、t: 判定値補正
  33. 生理的耐性xのOPが侵食度yに上昇した際の鉱石病判定を、ダイス数補正d、判定値補正tで行う。
  34. ダイス数補正と判定値補正は省略可能。例えば ORP60@25 は ORP60@25+D0+T0 と同義。
  35. また、ダイス数補正と判定値補正は逆順でも可。例えば ORP60@25+T10+D2 も可。
  36. ■ 増悪判定(--WORSENING)
  37. 症状を「末梢神経障害」「内臓機能不全」「精神症状」からランダムに選択。
  38. 継続ラウンド数を1d6+1で判定。
  39. ■ 中毒判定(--ADDICTION)
  40. 症状を「脳神経障害」「多臓器不全」「急性精神反応」からランダムに選択。
  41. ■ 判定の省略表記
  42. nADm、nABm、nABmにおいて、
  43. n(ダイス個数)を省略した場合、1として扱われる。
  44. m(ダイス種類)を省略した場合、100として扱われる。
  45. 例えば、AD<=90は1AD100<=90として解釈される。
  46. TEXT
  47. 1 register_prefix('[-+*/\d]*AD\d*', '[-+*/\d]*AB\d*', 'ORP', '--WORSENING', '--ADDICTION')
  48. 1 def initialize(command)
  49. 95 super(command)
  50. 95 @sort_add_dice = true # 加算ダイスでダイス目をソートする
  51. 95 @sort_barabara_dice = true # バラバラダイスでダイス目をソートする
  52. 95 @sides_implicit_d = 100 # 1D のようにダイスの面数が指定されていない場合に100面ダイスにする
  53. end
  54. 1 def eval_game_system_specific_command(command)
  55. 95 eval_ad(command) || eval_ab(command) || eval_orp(command) || eval_worsening(command) || eval_addiction(command)
  56. end
  57. 1 private
  58. 1 module Status
  59. 1 CRITICAL = 1
  60. 1 SUCCESS = 2
  61. 1 FAILURE = 3
  62. 1 ERROR = 4
  63. end
  64. STATUS_NAME = {
  65. 1 Status::CRITICAL => 'クリティカル!',
  66. Status::SUCCESS => '成功',
  67. Status::FAILURE => '失敗',
  68. Status::ERROR => 'エラー'
  69. }.freeze
  70. # クリティカル、エラー、成功失敗周りの閾値や優先関係が複雑かつルールが変動する可能性があるため、明示的にルール管理するための関数。
  71. 1 def check_roll(roll_result, target)
  72. 133 success = roll_result <= target
  73. crierror =
  74. 133 then: 25 if roll_result <= 10
  75. 25 else: 108 "Critical"
  76. 108 then: 23 elsif roll_result >= 91
  77. 23 "Error"
  78. else: 85 else
  79. 85 "Neutral"
  80. end
  81. result =
  82. 133 then: 21 if success && (crierror == "Critical")
  83. 21 else: 112 Status::CRITICAL
  84. 112 then: 64 elsif success && (crierror == "Neutral")
  85. 64 else: 48 Status::SUCCESS
  86. 48 then: 3 elsif success && (crierror == "Error")
  87. 3 else: 45 Status::SUCCESS
  88. 45 then: 4 elsif !success && (crierror == "Critical")
  89. 4 else: 41 Status::FAILURE
  90. 41 then: 21 elsif !success && (crierror == "Neutral")
  91. 21 else: 20 Status::FAILURE
  92. 20 then: 20 else: 0 elsif !success && (crierror == "Error")
  93. 20 Status::ERROR
  94. end
  95. 133 return result
  96. end
  97. 1 def eval_ad(command)
  98. # -は文字クラスの先頭または最後に置く。
  99. # そうしないと範囲指定子として解釈される。
  100. 95 m = %r{^([-+*/\d]*)AD(\d*)<=([-+*/\d]+)$}.match(command)
  101. 95 else: 14 then: 81 return nil unless m
  102. 14 times = m[1]
  103. 14 sides = m[2]
  104. 14 target = Arithmetic.eval(m[3], @round_type)
  105. 14 then: 3 else: 11 times = !times.empty? ? Arithmetic.eval(m[1], @round_type) : 1
  106. 14 then: 2 else: 12 sides = !sides.empty? ? sides.to_i : 100
  107. 14 roll_ad(command, times, sides, target)
  108. end
  109. 1 def eval_ab(command)
  110. 81 m = %r{^([-+*/\d]*)AB(\d*)<=([-+*/\d]+)(?:--([^\d\s]+)([0-2])?)?$}.match(command)
  111. 81 else: 46 then: 35 return nil unless m
  112. 46 times = m[1]
  113. 46 sides = m[2]
  114. 46 target = Arithmetic.eval(m[3], @round_type)
  115. 46 type = m[4]
  116. 46 type_status = m[5]
  117. 46 then: 39 else: 7 times = !times.empty? ? Arithmetic.eval(m[1], @round_type) : 1
  118. 46 then: 37 else: 9 sides = !sides.empty? ? sides.to_i : 100
  119. 46 then: 10 if !type_status.nil?
  120. 10 else: 36 type_status = type_status.to_i
  121. 36 then: 1 elsif type == "SNIPER" # スプレッドシート版キャラシの後方互換性のために必要
  122. 1 type_status = 1
  123. else: 35 else
  124. 35 type_status = 0
  125. end
  126. 46 then: 31 if type.nil?
  127. 31 roll_ab(command, times, sides, target)
  128. else: 15 else
  129. 15 roll_ab_withtype(command, times, sides, target, type, type_status)
  130. end
  131. end
  132. 1 def eval_orp(command)
  133. 35 m = %r{^ORP(?'END'[-+*/\d]+)@(?'ORP'[-+*/\d]+)(?:\+D(?'DICE'[-+*/\d]+))?(?:\+T(?'TGT'[-+*/\d]+))?$}.match(command)
  134. # D補正とT補正が逆順でも対応する
  135. 35 m ||= %r{^ORP(?'END'[-+*/\d]+)@(?'ORP'[-+*/\d]+)(?:\+T(?'TGT'[-+*/\d]+))?(?:\+D(?'DICE'[-+*/\d]+))?$}.match(command)
  136. 35 else: 28 then: 7 return nil unless m
  137. 28 endurance = Arithmetic.eval(m[:END], @round_type)
  138. 28 oripathy = Arithmetic.eval(m[:ORP], @round_type)
  139. 28 then: 9 else: 19 times_mod = !m[3].nil? ? Arithmetic.eval(m[:DICE], @round_type) : 0
  140. 28 then: 6 else: 22 target_mod = !m[4].nil? ? Arithmetic.eval(m[:TGT], @round_type) : 0
  141. 28 roll_orp(command, endurance, oripathy, times_mod, target_mod)
  142. end
  143. 1 def roll_ad(command, times, sides, target)
  144. 14 dice_list = @randomizer.roll_barabara(times, sides).sort
  145. 14 total = dice_list.sum
  146. 14 result = check_roll(total, target)
  147. 14 then: 13 if times == 1
  148. 13 result_text = "(#{command}) > #{dice_list.join(',')} > #{STATUS_NAME[result]}"
  149. else: 1 else
  150. 1 result_text = "(#{command}) > #{total}[#{dice_list.join(',')}] > #{STATUS_NAME[result]}"
  151. end
  152. 14 else: 0 case result
  153. when: 1 when Status::CRITICAL
  154. 1 Result.critical(result_text)
  155. when: 10 when Status::SUCCESS
  156. 10 Result.success(result_text)
  157. when: 2 when Status::FAILURE
  158. 2 Result.failure(result_text)
  159. when: 1 when Status::ERROR
  160. 1 Result.fumble(result_text)
  161. end
  162. end
  163. 1 def roll_ab(command, times, sides, target)
  164. 31 dice_list = @randomizer.roll_barabara(times, sides).sort
  165. 31 success_count, critical_count, error_count = process_ab(dice_list, target)
  166. 31 result_count = success_count + critical_count - error_count
  167. 31 result_text = "(#{command}) > [#{dice_list.join(',')}] > #{success_count}+#{critical_count}C-#{error_count}E > 成功数#{result_count}"
  168. 31 Result.new.tap do |r|
  169. 31 r.text = result_text
  170. 31 r.condition = result_count > 0
  171. 31 r.critical = critical_count > 0
  172. 31 r.fumble = error_count > 0
  173. end
  174. end
  175. 1 def roll_ab_withtype(command, times, sides, target, type, type_status)
  176. 15 dice_list = @randomizer.roll_barabara(times, sides).sort
  177. 15 success_count, critical_count, error_count = process_ab(dice_list, target)
  178. 15 result_count = success_count + critical_count - error_count
  179. 15 else: 0 case type
  180. when: 10 when "SNI"
  181. 10 then: 5 if (type_status == 0) && (result_count > 0)
  182. 5 result_mod = 1
  183. else: 5 else
  184. 5 result_mod = 0
  185. end
  186. when: 5 when "SNIPER" # スプレッドシート版キャラシの後方互換性のため残している
  187. 5 then: 3 if (type_status != 0) && (result_count > 0)
  188. 3 result_mod = 1
  189. else: 2 else
  190. 2 result_mod = 0
  191. end
  192. end
  193. 15 then: 15 if !result_mod.nil?
  194. 15 result_count += result_mod
  195. 15 result_text = "(#{command}) > [#{dice_list.join(',')}] > #{success_count}+#{critical_count}C-#{error_count}E+#{result_mod}(#{type}) > 成功数#{result_count}"
  196. else: 0 else
  197. result_text = "(#{command}) > [#{dice_list.join(',')}] > #{success_count}+#{critical_count}C-#{error_count}E > 成功数#{result_count}"
  198. end
  199. 15 Result.new.tap do |r|
  200. 15 r.text = result_text
  201. 15 r.condition = result_count > 0
  202. 15 r.critical = critical_count > 0
  203. 15 r.fumble = error_count > 0
  204. end
  205. end
  206. 1 ENDURANCE_LEVEL_TABLE = [20, 40, 70, 90, Float::INFINITY].freeze # 生理的耐性の実数値から能力評価への変換テーブル
  207. 1 ORP_TIMES_TABLE = [1, 2, 2, 3, 4].freeze # 生理的耐性の能力評価ごとのダイス数基本値
  208. 1 def roll_orp(command, endurance, oripathy, times_mod, target_mod)
  209. 28 sides = 100
  210. 102 endurance_level = ENDURANCE_LEVEL_TABLE.find_index { |n| endurance <= n }
  211. 28 original_times = ORP_TIMES_TABLE[endurance_level]
  212. 28 times = original_times + times_mod
  213. 28 then: 1 else: 27 if oripathy <= 20
  214. 1 return Result.new("(#{command}) > 鉱石病判定が発生しない侵食度です。侵食度は21以上を指定してください。")
  215. end
  216. 27 oripathy_stage = (oripathy / 20.0).ceil - 1
  217. 27 original_target = (80 - oripathy_stage * 20) - (oripathy - oripathy_stage * 20) * 5
  218. 27 target = original_target + target_mod
  219. 27 dice_and_target_text = "ダイス数#{original_times}" +
  220. 27 then: 9 else: 18 (times_mod > 0 ? "+#{times_mod}" : "") +
  221. "、判定値#{original_target}" +
  222. 27 then: 6 else: 21 (target_mod > 0 ? "+#{target_mod}" : "")
  223. 27 result_texts = ["(#{command})", dice_and_target_text, "#{times}B100<=#{target}"]
  224. 27 then: 6 else: 21 if target <= 0
  225. 6 result_texts += ["自動失敗!"]
  226. 6 return Result.failure(result_texts.join(" > "))
  227. end
  228. # 複数振ったダイスのうち1つでも判定値を下回れば成功なので、最も出目の小さいダイスのみを確認すればよい。
  229. # dice_listをソートした上で、dice_list[0]が最小の出目。
  230. 21 dice_list = @randomizer.roll_barabara(times, sides).sort
  231. 83 success_count = dice_list.count { |n| n <= target }
  232. 21 then: 18 if success_count > 0
  233. 18 result_texts += ["[#{dice_list.join(',')}]", "成功数#{success_count}", "成功"]
  234. 18 Result.success(result_texts.join(" > "))
  235. else: 3 else
  236. 3 result_texts += ["[#{dice_list.join(',')}]", "成功数#{success_count}", "失敗"]
  237. 3 Result.failure(result_texts.join(" > "))
  238. end
  239. end
  240. 1 def process_ab(dice_list, target)
  241. 46 success_count = 0
  242. 46 critical_count = 0
  243. 46 error_count = 0
  244. 46 dice_list.each do |value|
  245. 119 else: 0 case check_roll(value, target)
  246. when: 20 when Status::CRITICAL
  247. 20 critical_count += 1
  248. 20 success_count += 1
  249. when: 57 when Status::SUCCESS
  250. 57 when: 23 success_count += 1
  251. when Status::FAILURE
  252. # Nothing to do
  253. when: 19 when Status::ERROR
  254. 19 error_count += 1
  255. end
  256. end
  257. 46 return [success_count, critical_count, error_count]
  258. end
  259. 1 WORSENING_TABLE = [
  260. "末梢神経障害",
  261. "内臓機能不全",
  262. "精神症状",
  263. ].freeze
  264. 1 def eval_worsening(command)
  265. 7 then: 3 else: 4 return nil if command != "--WORSENING"
  266. 4 value = @randomizer.roll_once(3)
  267. 4 chosen = WORSENING_TABLE[value - 1]
  268. 4 elapse = @randomizer.roll_once(6) + 1
  269. 4 return "--WORSENING > #{chosen}: #{elapse} rounds"
  270. end
  271. 1 ADDICTION_TABLE = [
  272. "脳神経障害",
  273. "多臓器不全",
  274. "急性精神症状",
  275. ].freeze
  276. 1 def eval_addiction(command)
  277. 3 then: 0 else: 3 return nil if command != "--ADDICTION"
  278. 3 value = @randomizer.roll_once(3)
  279. 3 chosen = ADDICTION_TABLE[value - 1]
  280. 3 return "--ADDICTION > #{chosen}"
  281. end
  282. end
  283. end
  284. end

lib/bcdice/game_system/ArsMagica.rb

82.56% lines covered

68.29% branches covered

86 relevant lines. 71 lines covered and 15 lines missed.
41 total branches, 28 branches covered and 13 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/normalize"
  3. 1 require "bcdice/format"
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class ArsMagica < Base
  7. # ゲームシステムの識別子
  8. 1 ID = 'ArsMagica'
  9. # ゲームシステム名
  10. 1 NAME = 'アルスマギカ'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = 'あるすまきか'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  15. ・ストレスダイス (ArSx+y)
  16.  "ArS(ボッチダイス)+(修正)"です。判定にも使えます。Rコマンド(1R10+y[m])に読替をします。
  17.  ボッチダイスと修正は省略可能です。(ボッチダイスを省略すると1として扱います)
  18.  botchダイスの0の数が2以上の時は、数えて表示します。
  19.  (注意!) botchの判断が発生したときには、そのダイスを含めてロールした全てのダイスを[]の中に並べて表示します。
  20.  例) (1R10[5]) > 0[0,1,8,0,8,1] > Botch!
  21.   最初の0が判断基準で、その右側5つがボッチダイスです。1*2,8*2,0*1なので1botchという訳です。
  22. INFO_MESSAGE_TEXT
  23. 1 register_prefix('ArS', '1R10')
  24. 1 def eval_game_system_specific_command(string)
  25. 38 else: 38 then: 0 unless parse_ars(string) || parse_1r10(string)
  26. return nil
  27. end
  28. 38 diff = @target_numner || 0
  29. 38 botch = @botch
  30. 38 bonus = @modify_number
  31. 38 crit_mul = 1
  32. 38 total = 0
  33. 38 cmp_op = @cmp_op
  34. 38 die = @randomizer.roll_once(10) - 1
  35. 38 output = "(#{expr()}) > "
  36. 38 then: 5 if die == 0 # botch?
  37. 5 count0 = 0
  38. 5 dice_n = []
  39. 5 botch.times do |_i|
  40. 25 botch_die = @randomizer.roll_once(10) - 1
  41. 25 then: 2 else: 23 count0 += 1 if botch_die == 0
  42. 25 dice_n.push(botch_die)
  43. end
  44. 5 output += "0[#{die},#{dice_n.join(',')}]"
  45. 5 then: 1 if count0 != 0
  46. 1 then: 1 if count0 > 1
  47. 1 output += " > #{count0}Botch!"
  48. else: 0 else
  49. output += " > Botch!"
  50. end
  51. # Botchの時には目標値を使った判定はしない
  52. 1 cmp_op = nil
  53. else: 4 else
  54. 4 then: 0 if bonus > 0
  55. else: 4 output += "+#{bonus} > #{bonus}"
  56. 4 then: 0 elsif bonus < 0
  57. output += "#{bonus} > #{bonus}"
  58. else: 4 else
  59. 4 output += " > 0"
  60. end
  61. 4 total = bonus
  62. else: 33 end
  63. 33 then: 4 elsif die == 1 # Crit
  64. 4 crit_dice = ""
  65. 4 body: 5 while die == 1
  66. 5 crit_mul *= 2
  67. 5 die = @randomizer.roll_once(10)
  68. 5 crit_dice += "#{die},"
  69. end
  70. 4 total = die * crit_mul
  71. 4 crit_dice = crit_dice.sub(/,$/, '')
  72. 4 output += total.to_s
  73. 4 output += "[1,#{crit_dice}]"
  74. 4 total += bonus
  75. 4 then: 0 if bonus > 0
  76. else: 4 output += "+#{bonus} > #{total}"
  77. 4 then: 0 else: 4 elsif bonus < 0
  78. output += "#{bonus} > #{total}"
  79. end
  80. else: 29 else
  81. 29 total = die + bonus
  82. 29 then: 3 if bonus > 0
  83. 3 else: 26 output += "#{die}+#{bonus} > #{total}"
  84. 26 then: 1 elsif bonus < 0
  85. 1 output += "#{die}#{bonus} > #{total}"
  86. else: 25 else
  87. 25 output += total.to_s
  88. end
  89. end
  90. 38 then: 3 else: 35 if cmp_op == :>=
  91. 3 then: 2 else: 1 output += (total >= diff ? " > 成功" : " > 失敗")
  92. end
  93. 38 return output.to_s
  94. end
  95. 1 private
  96. 1 def parse_ars(command)
  97. 38 m = /^ArS(\d+)?((?:[+-]-?\d+)+)?(?:([>=]+)(\d+))?$/i.match(command)
  98. 38 else: 38 then: 0 unless m
  99. return false
  100. end
  101. 38 then: 35 else: 3 @botch = m[1]&.to_i || 1
  102. 38 @modify_number = ArithmeticEvaluator.eval(m[2] || "")
  103. 38 @cmp_op = Normalize.comparison_operator(m[3])
  104. 38 then: 4 else: 34 @target_numner = m[4]&.to_i
  105. 38 return true
  106. end
  107. 1 def parse_1r10(command)
  108. m = /^1R10((?:[+-]-?\d+)+)?(?:\[(\d+)\])?(?:([>=]+)(\d+))?$/i.match(command)
  109. else: 0 then: 0 unless m
  110. return false
  111. end
  112. @modify_number = ArithmeticEvaluator.eval(m[1] || "")
  113. then: 0 else: 0 @botch = m[2]&.to_i || 1
  114. @cmp_op = Normalize.comparison_operator(m[3])
  115. then: 0 else: 0 @target_numner = m[4]&.to_i
  116. return true
  117. end
  118. 1 def expr()
  119. 38 modifier = Format.modifier(@modify_number)
  120. 38 "1R10#{modifier}[#{@botch}]#{@cmp_op}#{@target_numner}"
  121. end
  122. end
  123. end
  124. end

lib/bcdice/game_system/AssaultEngine.rb

97.96% lines covered

90.0% branches covered

49 relevant lines. 48 lines covered and 1 lines missed.
20 total branches, 18 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class AssaultEngine < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'AssaultEngine'
  7. # ゲームシステム名
  8. 1 NAME = 'アサルトエンジン'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'あさるとえんしん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定 AEt (t目標値)
  14. 例: AE45 (目標値45)
  15. ・リロール nAEt (nロール前の値、t目標値)
  16. 例: 76AE45 (目標値45で、76を振り直す)
  17. ・スワップ(t目標値) エネミーブックP11
  18. 例: AES45 (目標値45、スワップ表示あり)
  19. MESSAGETEXT
  20. 1 register_prefix('\d*AE')
  21. 1 def initialize(command)
  22. 18 super(command)
  23. 18 @round_type = RoundType::FLOOR # 端数切り捨て
  24. end
  25. 1 def eval_game_system_specific_command(command)
  26. 16 cmd = Command::Parser.new(/AES?/, round_type: round_type).enable_prefix_number
  27. .has_suffix_number.parse(command)
  28. 16 else: 16 then: 0 return nil unless cmd
  29. 16 target = cmd.suffix_number
  30. 16 then: 1 else: 15 target = 99 if target >= 100
  31. 16 then: 4 if cmd.command.include?("AES") # SWAP初回
  32. 4 total = @randomizer.roll_once(100) % 100 # 0-99
  33. 4 swap = (total % 10) * 10 + (total / 10)
  34. 4 r1 = judge(target, total)
  35. 4 r2 = judge(target, swap)
  36. 4 text = "(AES#{format00(target)}) > #{r1.text} / スワップ#{r2.text}"
  37. 4 else: 12 return_result(r1, r2, text)
  38. 12 then: 8 elsif cmd.prefix_number.nil? # 初回ロール
  39. 8 total = @randomizer.roll_once(100) % 100 # 0-99
  40. 8 judge(target, total).tap do |r|
  41. 8 r.text = "(AE#{format00(target)}) > #{r.text}"
  42. end
  43. else: 4 else # リロール
  44. 4 now = cmd.prefix_number
  45. 4 die = @randomizer.roll_once(10) % 10 # 0-9
  46. 4 new1 = judge(target, (now / 10 * 10) + die) # 1の位を振り直す
  47. 4 new2 = judge(target, now % 10 + die * 10) # 10の位を振り直す
  48. 4 text = "(#{format00(now)}AE#{format00(target)}) > #{die} > #{new1.text} / #{new2.text}"
  49. 4 return_result(new1, new2, text)
  50. end
  51. end
  52. 1 def format00(dice)
  53. 44 format("%02d", dice)
  54. end
  55. 1 def return_result(result1, result2, text)
  56. 8 then: 3 if result1.critical? || result2.critical?
  57. 3 else: 5 Result.critical(text)
  58. 5 then: 3 elsif result1.success? || result2.success?
  59. 3 else: 2 Result.success(text)
  60. 2 then: 0 elsif result1.fumble? && result2.fumble?
  61. Result.fumble(text)
  62. else: 2 else
  63. 2 Result.failure(text)
  64. end
  65. end
  66. 1 def judge(target, total)
  67. 24 double = (total / 10) == (total % 10)
  68. 24 total_text = format00(total)
  69. 24 then: 15 if total <= target
  70. 15 then: 10 else: 5 double ? Result.critical("(#{total_text})クリティカル") : Result.success("(#{total_text})成功")
  71. else: 9 else
  72. 9 then: 1 else: 8 double ? Result.fumble("(#{total_text})ファンブル") : Result.failure("(#{total_text})失敗")
  73. end
  74. end
  75. end
  76. end
  77. end

lib/bcdice/game_system/Avandner.rb

97.78% lines covered

90.91% branches covered

45 relevant lines. 44 lines covered and 1 lines missed.
11 total branches, 10 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Avandner < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Avandner'
  7. # ゲームシステム名
  8. 1 NAME = '黒絢のアヴァンドナー'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'こつけんのあうあんとなあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・調査判定:nAVm[Cx]
  14. ・命中判定:nAVm*p[+t][Cx]
  15. []内は省略可能。
  16. クリティカルヒットの分だけ、自動で振り足し処理を行います。0
  17. 「n」でダイス数を指定。
  18. 「m」で目標値を指定。省略は出来ません。
  19. 「Cx」でクリティカル値を指定。省略時は「1」、最大値は「2」、「0」でクリティカル無し。
  20. 「p」で攻撃力を指定。「*」は「x」でも可。
  21. 「+t」でクリティカルトリガーを指定。省略可能です。
  22. 攻撃力指定で命中判定となり、成功数ではなく、ダメージを結果表示します。
  23. 【書式例】
  24. ・5AV3 → 5d10で目標値3。
  25. ・6AV2C0 → 6d10で目標値2。クリティカル無し。
  26. ・4AV3*5 → 4d10で目標値3、攻撃力5の命中判定。
  27. ・7AV2x10 → 7d10で目標値2、攻撃力10の命中判定。
  28. ・8av4*7+10 → 8d10で目標値4、攻撃力7、クリティカルトリガー10の命中判定。
  29. MESSAGETEXT
  30. 1 register_prefix('\d+AV')
  31. 1 def initialize(command)
  32. 21 super(command)
  33. 21 @sort_add_dice = true # ダイスのソート有
  34. end
  35. 1 def eval_game_system_specific_command(command)
  36. # AVコマンド:調査判定, 成功判定
  37. 21 then: 21 else: 0 if command =~ /(\d+)AV(\d+)((x|\*)(\d+))?(\+(\d+))?(C(\d+))?$/i
  38. 21 diceCount = Regexp.last_match(1).to_i
  39. 21 target = Regexp.last_match(2).to_i
  40. 21 damage = (Regexp.last_match(5) || 0).to_i
  41. 21 criticalTrigger = (Regexp.last_match(7) || 0).to_i
  42. 21 criticalNumber = (Regexp.last_match(9) || 1).to_i.clamp(0, 2)
  43. 21 return checkRoll(diceCount, target, damage, criticalTrigger, criticalNumber)
  44. end
  45. return nil
  46. end
  47. 1 def checkRoll(diceCount, target, damage, criticalTrigger, criticalNumber)
  48. 21 totalSuccessCount = 0
  49. 21 totalCriticalCount = 0
  50. 21 text = ""
  51. 21 rollCount = diceCount
  52. 21 body: 32 while rollCount > 0
  53. 32 diceArray = @randomizer.roll_barabara(rollCount, 10).sort
  54. 32 diceText = diceArray.join(",")
  55. 159 successCount = diceArray.count { |i| i <= target }
  56. 159 criticalCount = diceArray.count { |i| i <= criticalNumber }
  57. 32 totalSuccessCount += successCount
  58. 32 totalCriticalCount += criticalCount
  59. 32 else: 21 then: 11 text += "+" unless text.empty?
  60. 32 text += "#{successCount}[#{diceText}]"
  61. 32 rollCount = criticalCount
  62. end
  63. 21 result = ""
  64. 21 isDamage = (damage != 0)
  65. 21 then: 13 if isDamage
  66. 13 totalDamage = totalSuccessCount * damage + totalCriticalCount * criticalTrigger
  67. 13 result += "(#{diceCount}D10\<\=#{target}) > #{text} > Hits:#{totalSuccessCount}*#{damage}"
  68. 13 then: 4 else: 9 result += " + Trigger:#{totalCriticalCount}*#{criticalTrigger}" if criticalTrigger > 0
  69. 13 result += " > #{totalDamage}ダメージ"
  70. else: 8 else
  71. 8 result += "(#{diceCount}D10\<\=#{target}) > #{text} > 成功数:#{totalSuccessCount}"
  72. end
  73. 21 then: 9 else: 12 result += " / #{totalCriticalCount}クリティカル" if totalCriticalCount > 0
  74. 21 return result
  75. end
  76. end
  77. end
  78. end

lib/bcdice/game_system/Ayabito.rb

100.0% lines covered

100.0% branches covered

44 relevant lines. 44 lines covered and 0 lines missed.
18 total branches, 18 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/command/parser'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Ayabito < Base
  6. # ゲームシステムの識別子
  7. 1 ID = "Ayabito"
  8. # ゲームシステム名
  9. 1 NAME = "あやびと"
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = "あやひと"
  12. 1 HELP_MESSAGE = <<~TEXT
  13. ・判定コマンド(xAB±y@c$d>=z)
  14. x:サイコロの数(10以上の場合9個振り、それ以降を成功数2として加算する)
  15. ±y:成功数への補正(省略可)
  16. c:クリティカル値(@ごと省略可。省略時は6)
  17. d:出目を2として数える数の最小値($ごと省略可。省略時は6)
  18. z:目標値(妨害値など。>=ごと省略可)
  19. (例) 4AB
  20. 11AB>=5
  21. 5AB+1
  22. 6AB@5>=3
  23. ・各種表
  24. 感情表 ET
  25. 帝都東京シーン表 TST / 場面演出シーン表 BST
  26. 交流表 CET
  27. ファンブル表 FT
  28. 封印期間表 LT
  29. 帝都東京エリア選択 TET
  30.  浅草シーン表 AST
  31.  上野シーン表 UST
  32.  日本橋シーン表 NST
  33.  銀座シーン表 GST
  34.  霞ヶ関シーン表 KST
  35.  新宿シーン表 SST
  36. TEXT
  37. 1 def initialize(command)
  38. 41 super(command)
  39. 41 @sort_barabara_dice = true
  40. 41 @round_type = RoundType::CEIL
  41. end
  42. 1 def eval_game_system_specific_command(command)
  43. 41 return check_action(command) || roll_tables(command, TABLES)
  44. end
  45. 1 def check_action(command)
  46. 41 parser = Command::Parser.new("AB", round_type: RoundType::CEIL).has_prefix_number.enable_critical.enable_dollar.restrict_cmp_op_to(nil, :>=)
  47. 41 parsed = parser.parse(command)
  48. 41 then: 16 else: 25 return nil if parsed.nil?
  49. 25 then: 21 if parsed.prefix_number < 10
  50. 21 dice_cnt = parsed.prefix_number
  51. 21 over_modify = 0
  52. else: 4 else
  53. 4 dice_cnt = 9
  54. 4 over_modify = parsed.prefix_number - 9
  55. end
  56. 25 modify = parsed.modify_number
  57. 25 critical_target = parsed.critical || 6
  58. 25 addition_target = parsed.dollar || 6
  59. 25 target = parsed.target_number
  60. 25 dice_arr = @randomizer.roll_barabara(dice_cnt, 6).sort
  61. 25 dice_str = dice_arr.join(",")
  62. 168 has_critical = dice_arr.any? { |x| x >= critical_target }
  63. 317 success_cnt = dice_arr.count { |x| x >= 4 } + dice_arr.count { |x| x >= addition_target } + over_modify * 2
  64. 25 has_fumble = success_cnt == 0 && dice_arr.include?(1)
  65. 25 then: 3 if has_fumble
  66. 3 success_cnt = 0
  67. else: 22 else
  68. 22 success_cnt += modify
  69. end
  70. 25 then: 10 else: 15 result = target.nil? ? success_cnt >= 1 : success_cnt >= target
  71. 25 Result.new.tap do |r|
  72. 25 then: 4 else: 21 then: 4 else: 21 then: 14 else: 11 then: 9 else: 16 then: 3 else: 22 r.text = "(#{dice_cnt}B6>=4)#{over_modify > 0 ? "+#{over_modify * 2}" : ''} > [#{dice_str}]#{over_modify > 0 ? "+#{over_modify * 2}" : ''} > 成功数#{success_cnt} > #{result ? '成功' : '失敗'}#{has_critical ? '(クリティカル)' : ''}#{has_fumble ? '(ファンブル)' : ''}"
  73. 25 r.critical = has_critical
  74. 25 r.fumble = has_fumble
  75. 25 r.success = result
  76. 25 r.failure = !result
  77. end
  78. end
  79. TABLES = {
  80. 1 'ET' => DiceTable::D66Table.new(
  81. '感情表',
  82. D66SortType::NO_SORT,
  83. {
  84. 11 => '信頼/不信感',
  85. 12 => '好奇心/無関心',
  86. 13 => '優越感/劣等感',
  87. 14 => '好意/敵意',
  88. 15 => '安心感/不安感',
  89. 16 => '愛情/偏愛',
  90. 21 => '同情/憐憫',
  91. 22 => '親近感/疎外感',
  92. 23 => '連帯感/隔意',
  93. 24 => '尽力/面倒',
  94. 25 => '貸し/借り',
  95. 26 => '庇護欲/食傷',
  96. 31 => '期待/反発',
  97. 32 => '熱狂/心酔',
  98. 33 => '幸福感/不快感',
  99. 34 => '尊敬/軽蔑',
  100. 35 => '憧憬/嫉妬',
  101. 36 => '忠誠/服従',
  102. 41 => '友情/侮蔑',
  103. 42 => '競争心/警戒',
  104. 43 => '感謝/後悔',
  105. 44 => '感服/恐怖',
  106. 45 => '興味/屈辱',
  107. 46 => '誠意/憎悪',
  108. 51 => '羨望/嫌悪',
  109. 52 => '共感/懸念',
  110. 53 => '傾倒/厭気',
  111. 54 => '赦し/怒り',
  112. 55 => '有為/苦手',
  113. 56 => '恩義/不満',
  114. 61 => '予感/困惑',
  115. 62 => '懐旧/忘却',
  116. 63 => '慕情/執着',
  117. 64 => '夢中/退屈',
  118. 65 => '贖罪/罪悪感',
  119. 66 => '慈愛/殺意',
  120. }
  121. ),
  122. 'TST' => DiceTable::D66LeftRangeTable.new(
  123. '帝都東京シーン表',
  124. D66SortType::NO_SORT,
  125. [
  126. [1..1, Array.new(6, "子~巳までの任意の十二支を選択する。")],
  127. [2..3, [
  128. "[子]帝国大学の赤門、学生たちが今日も勉学に励んでいる。",
  129. "[丑]吉原の歓楽街。昼間は静かだが、夜は活気を見せてくれる。",
  130. "[寅]上野公園。桜に新緑、紅葉など、季節の顔を見せてくれる。",
  131. "[卯]浅草六区は今日も賑やか。浅草寺や仲見世には、多くの人々が行き交う。",
  132. "[辰]凌雲閣。浅草十二階として親しまれる塔に昇り、周囲を一望する。",
  133. "[巳]丸の内の東京駅。構内の喧騒とは裏腹に、霞ヶ関は静かに時が流れる。",
  134. ]],
  135. [4..5, [
  136. "[午]銀座をぶらぶらと歩く。百貨店が立ち並ぶこの街では、何でも買うことができるらしい。",
  137. "[未]日比谷の帝国劇場。演目は、話題のトップスタアによる華やかなる歌劇のようだ。",
  138. "[申]皇居のほとり。水面にうかぶ蓮の葉が、しずかに揺れている。",
  139. "[酉]明治神宮の境内。神聖なる雰囲気を味わうことができる。",
  140. "[戌]新たな東京の名所である新宿。今では東西を二分する街である。",
  141. "[亥]日本帝国軍駐屯地。妖怪人間共同実働部隊の本部も敷地内にある。",
  142. ]],
  143. [6..6, Array.new(6, "午~亥まで任意の十二支を選択する。")],
  144. ]
  145. ),
  146. 'BST' => DiceTable::D66LeftRangeTable.new(
  147. '場面演出シーン表',
  148. D66SortType::NO_SORT,
  149. [
  150. [1..1, Array.new(6, "子~巳までの任意の十二支を選択する。")],
  151. [2..3, [
  152. "[子]人々が寝静まる帝都の夜。月に雲がかかるとともに、魔の香りが漂っている。",
  153. "[丑]草木も眠る静けさの中、犬の遠吠えだけが聞こえてくる。",
  154. "[寅]一陣の風が吹き抜ける。風に乗った匂いが、妙に鼻をくすぐってきた。",
  155. "[卯]霧や朝もやに包まれる。向こうに見える姿は誰だろうか……",
  156. "[辰]帝都に朝日が射す。人々は起き出し、日々の営みを始める。",
  157. "[巳]清廉な雰囲気の風景。鳥や虫の声、風にそよぐ木々の音が聞こえてくる。",
  158. ]],
  159. [4..5, [
  160. "[午]時計の針がある時間を指し示す。刻を告げるチャイムや鐘が響き渡る。",
  161. "[未]昼間の大通り。自動車や路面電車が走り、行き交う人々の雑踏が至るところで見られる。",
  162. "[申]夕刻、どこからともなく、定かではない声や物音が漏れてくる。",
  163. "[酉]瓦斯灯(がすとう)が通りを鮮やかに照らす。夜が街のもうひとつの顔を出し始める。",
  164. "[戌]星空の下、月明かりが微かに夜道を照らしている。",
  165. "[亥]光ひとつない暗闇の中。何者かの気配が蠢いている……",
  166. ]],
  167. [6..6, Array.new(6, "午~亥まで任意の十二支を選択する。")],
  168. ]
  169. ),
  170. 'CET' => DiceTable::D66LeftRangeTable.new(
  171. '交流表',
  172. D66SortType::NO_SORT,
  173. [
  174. [1..1, Array.new(6, "感情~性格までの任意のテーマを選択する。")],
  175. [2..3, [
  176. "[感情]相手に抱いている感情、伝えるべきか伝えないべきか。",
  177. "[人間]相手に人間という存在をどう思うか、聞いてみるとしよう。",
  178. "[友達]相手に友人や仲間について語ろう。話すことで分かる想いもあるだろう。",
  179. "[告白]相手に話していいか分からないが、自分の秘めたる想いを語ろう。",
  180. "[思い出]相手に、過去の思い出を話してみよう。相手から昔話をきけるかもしれない。",
  181. "[性格]相手に自身の性格を語ろう。表向きのみ話すか、奥底まで話してしまうかは、事と次第による。",
  182. ]],
  183. [4..5, [
  184. "[関係性]相手とは、いつからこうした関係だったのか。相手と関係性について話そう。",
  185. "[妖怪]相手に妖怪という存在をどう思うか、聞いてみるとしよう。",
  186. "[あやびと]相手に、自分があやびとである意味や意義を語ってみよう。",
  187. "[想い]相手が今、何かしら想う人や物事について聞いてみよう。",
  188. "[夢]相手に自分の夢を語ろう。未来の夢、かつて捨てた夢かもしれない。",
  189. "[半生]相手に自身の半生を語ろう。半生こそが、今の自分となるきっかけなのだから……",
  190. ]],
  191. [6..6, Array.new(6, "関係性~半生までの任意のテーマを選択する。")],
  192. ]
  193. ),
  194. 'FT' => DiceTable::Table.new(
  195. 'ファンブル表',
  196. '1D6',
  197. [
  198. 'PCの【耐久値】を-5する(最低1)。',
  199. 'PCの【活力値】を-5する(最低1)',
  200. 'PCは戦闘ないしフェイズが終了するまで《アビリティ》を使用できない。',
  201. 'PCは戦闘ないしフェイズが終了するまで[絆]を使用できない。',
  202. 'セッション終了時まで、登場するエネミーすべての【耐久値】を+3する',
  203. 'セッション終了時まで、登場するエネミーすべてのダメージを+2する。',
  204. ]
  205. ),
  206. 'LT' => DiceTable::Table.new(
  207. '封印期間表',
  208. '1D6',
  209. [
  210. # '1日',
  211. '1週間',
  212. '1ヶ月',
  213. '1年',
  214. '10年',
  215. '50年',
  216. '100年',
  217. # '500年',
  218. ]
  219. ),
  220. 'TET' => DiceTable::Table.new(
  221. '帝都東京エリア選択',
  222. '1D6',
  223. [
  224. '浅草。庶民の盛り場として賑わう商店街と下町。',
  225. '上野。あらゆる路線の中心である帝都の玄関口。',
  226. '日本橋。江戸時代から変わらぬ商業の中心地。',
  227. '銀座。赤煉瓦が立ち並ぶ、帝都一モダンな繁華街。',
  228. '霞ヶ関。国会議事堂や裁判所がある官庁街。',
  229. '新宿。関東大震災以降、急速に発展した新しい街。',
  230. ]
  231. ),
  232. 'AST' => DiceTable::D66LeftRangeTable.new(
  233. '浅草シーン表',
  234. D66SortType::NO_SORT,
  235. [
  236. [1..1, Array.new(6, "子~巳までの任意の十二支を選択する。")],
  237. [2..3, [
  238. "[子]浅草寺。浅草の顔ともいえる寺。7世紀に建造された都内でも最古の寺。",
  239. "[丑]武神一刀流道場。浅草でも有名な剣術道場。柔術や薙刀など、剣以外の実践的な技も教えている。",
  240. "[寅]待乳の渡し。隅田川を橋で渡る代わりに、乗せて渡ってくれる小舟。",
  241. "[卯]帝都観光案内館。帝都東京内観光の案内所。ガイドつきのバス観光も行っている。",
  242. "[辰]神谷バー。老舗の飲食店であり、電気ブランを提供していることで有名。",
  243. "[巳]雷門。浅草寺の南側に建てられた門で、風神と雷神の像が安置されている。",
  244. ]],
  245. [4..5, [
  246. "[午]仲見世。雷門から浅草寺本堂に続く仁王門まで立ち並ぶ商店街。",
  247. "[未]仰天堂。やたらと大盛りの食事を提供してくれる人気店。",
  248. "[申]混沌興行。妖怪たちが演じることで有名な見世物小屋。いつも混み合っている。",
  249. "[酉]浅草六区。浅草の中心街であり、店舗や演芸場、活動写真館が並んでいる。",
  250. "[戌]凌雲閣。浅草十二階とも呼ばれる塔。関東大震災でも崩れることなく、そびえ立っている。",
  251. "[亥]花屋敷。日本最初の遊園地であり、園内には動物園も完備している。",
  252. ]],
  253. [6..6, Array.new(6, "午~亥まで任意の十二支を選択する。")],
  254. ]
  255. ),
  256. 'UST' => DiceTable::D66LeftRangeTable.new(
  257. '上野シーン表',
  258. D66SortType::NO_SORT,
  259. [
  260. [1..1, Array.new(6, "子~巳までの任意の十二支を選択する。")],
  261. [2..3, [
  262. "[子]上野恩賜公園。桜の名所でもある巨大な公園。敷地内では、四季折々の自然を楽しむことができる。",
  263. "[丑]東京帝室博物館。宮内省所管の博物館であり、珍しい品々が展示されている。",
  264. "[寅]上野駅。帝都と地方の路線を繋ぐ駅。地方から上京してくる人々を多く見かける。",
  265. "[卯]精養軒。本格的な洋食が楽しめる老舗のレストラン。人間、妖怪に限らず上流階級が通っている。",
  266. "[辰]御徒町。高架下と周辺に所狭しと民家や長屋、様々な店がひしめきあう下町の歓楽街。",
  267. "[巳]一鉄工場。偏屈で頑固だが有能な老人が経営する工場。自作のラジオが置かれている。",
  268. ]],
  269. [4..5, [
  270. "[午]帝国大学。象徴の赤門が有名な、日本の最高学府。校内には、妖怪研究室がある。",
  271. "[未]鳳明館。明治創業の旅館。文士が執筆する際に、よく利用している。",
  272. "[申]黄龍門学園。帝国大学敷地の横にある私立学園。妖怪や半妖も多く通っている。",
  273. "[酉]不忍池。弁天堂と大黒天堂を構える池で、河童が隠れ住んでいる。",
  274. "[戌]きさらぎ長屋。行く宛のない者や、行き場をなくした者が集まる長屋。",
  275. "[亥]上野恩賜公園動物園。ホッキョクグマ舎やサル山をはじめ、珍しい動物が飼われている。",
  276. ]],
  277. [6..6, Array.new(6, "午~亥まで任意の十二支を選択する。")],
  278. ]
  279. ),
  280. 'NST' => DiceTable::D66LeftRangeTable.new(
  281. '日本橋シーン表',
  282. D66SortType::NO_SORT,
  283. [
  284. [1..1, Array.new(6, "子~巳までの任意の十二支を選択する。")],
  285. [2..3, [
  286. "[子]日本銀行本店。西洋建築の先駆けといえる建築物。帝都事変では大きな被害が出た。",
  287. "[丑]三越。日本橋に居を構える有数の大型百貨店。この店で揃わぬ物はないとされている。",
  288. "[寅]日本橋。五つ街道の起点であり、東海道五十三次の出発点としてよく知られる橋。",
  289. "[卯]メイゾン妖の巣。妖怪や半妖の文学者たちが集うカフェー。",
  290. "[辰]大正座。明治座の兄弟とよばれる演芸場。歌舞伎や芝居などが上演されている。",
  291. "[巳]多々良堂。江戸時代より続く退魔具の専門店。多くのあやびとが訪れる。",
  292. ]],
  293. [4..5, [
  294. "[午]妖艶大世界。上海にある上海大世界を真似て、妖怪や半妖が集まってできた新興の花街。",
  295. "[未]二丁巴里。丸ノ内の一丁倫敦に対して創られた大規模な問屋街。",
  296. "[申]皇居外苑。桔梗門の前は大広場があり、皇居を訪れる者が集まっている。",
  297. "[酉]東京駅。皇居に対面する形で作られた煉瓦造りの壮麗な駅。",
  298. "[戌]丸ノ内ビルヂング。大正12年に竣工した東洋一ともいわれる巨大なビルヂング。",
  299. "[亥]将門塚。平将門公の御首が祀られる塚。大手町にひっそりと存在している。",
  300. ]],
  301. [6..6, Array.new(6, "午~亥まで任意の十二支を選択する。")],
  302. ]
  303. ),
  304. 'GST' => DiceTable::D66LeftRangeTable.new(
  305. '銀座シーン表',
  306. D66SortType::NO_SORT,
  307. [
  308. [1..1, Array.new(6, "子~巳までの任意の十二支を選択する。")],
  309. [2..3, [
  310. "[子]ダンスホウル・ガアデン。モダンボーイやモダンガール御用達の帝都東京有数のダンスホウル。",
  311. "[丑]服部時計店。銀座のシンボルとなっている時計塔と、併設された店舗。",
  312. "[寅]松屋。大正14年に開店した百貨店。地上7階までの吹き抜けステンドグラスで知られる。",
  313. "[卯]歌舞伎座。歌舞伎の殿堂。古式ゆかしい意匠を取り入れた最新建築の劇場。",
  314. "[辰]倫敦橋。文士や芸術家が好んで訪れる2階建ての洋式建築のカフェー。",
  315. "[巳]資生堂パーラー。ソーダ水やアイスクリンを提供したことで有名な喫茶店。",
  316. ]],
  317. [4..5, [
  318. "[午]カフェープランタン。日本初のカフェーといわれる老舗。富裕層やインテリ層が多く訪れる。",
  319. "[未]新橋絢爛花街。関東大震災をきっかけに再建された花街。政府高官なども利用している。",
  320. "[申]鹿鳴館。明治時代を代表する西洋建築。華族や資産家が利用できる施設となっている。",
  321. "[酉]帝国ホテル。フランク・ロイド・ライトが設計した最新鋭の技術が詰め込まれたホテル。",
  322. "[戌]妖務省本部。妖務省と妖怪人間共同実働部隊の本部が置かれている。",
  323. "[亥]帝国劇場。明治時代を代表する日本最大の大劇場で\"帝劇\"の愛称で知られている。",
  324. ]],
  325. [6..6, Array.new(6, "午~亥まで任意の十二支を選択する。")],
  326. ]
  327. ),
  328. 'KST' => DiceTable::D66LeftRangeTable.new(
  329. '霞ヶ関シーン表',
  330. D66SortType::NO_SORT,
  331. [
  332. [1..1, Array.new(6, "子~巳までの任意の十二支を選択する。")],
  333. [2..3, [
  334. "[子]桜田門。内堀にある門のひとつで皇居に通じている。",
  335. "[丑]警視庁庁舎。警視庁の総合本部。庁舎内に妖鬼対策本部がある。",
  336. "[寅]日比谷公園。市民の憩いの場所であり、図書館や音楽堂をそなえる大規模な公園。",
  337. "[卯]大審院庁舎。司法裁判所の中における最上級審の裁判所。",
  338. "[辰]私立聖ロザリオ女学園。愛宕山の森に囲まれた都内随一のお嬢様学校。",
  339. "[巳]片倉組。武家屋敷を改装した本邸であり、帝都屈指のヤクザの根城となっている。",
  340. ]],
  341. [4..5, [
  342. "[午]妖人史料編纂局。妖怪の史料の収集と編纂を目的として設置された官立組織。",
  343. "[未]鰐淵金融。利子こそ高いが、誰にでも門戸を開いている貸金業者。",
  344. "[申]料亭山王園。政治家や官僚御用達の料亭。十二真鬼も出入りしている。",
  345. "[酉]日枝神社。山王祭で知られる神社。数多くの刀剣が納められている。",
  346. "[戌]国会議事堂。現在建設中の国会議事堂。大正25年に竣工予定で、現在は木造の仮議事堂がある。",
  347. "[亥]帝国図書館。国立図書館で、国内で出版されたあらゆる書籍が収蔵されている。",
  348. ]],
  349. [6..6, Array.new(6, "午~亥まで任意の十二支を選択する。")],
  350. ]
  351. ),
  352. 'SST' => DiceTable::D66LeftRangeTable.new(
  353. '新宿シーン表',
  354. D66SortType::NO_SORT,
  355. [
  356. [1..1, Array.new(6, "子~巳までの任意の十二支を選択する。")],
  357. [2..3, [
  358. "[子]武蔵野館。座席数1,200を誇る国内有数の活動大写真館。",
  359. "[丑]二幸。食料品専門百貨店。あやびとたちに友好的で、伝奇事件が解決すると飲食が提供される。",
  360. "[寅]高野フルーツパーラー。マスクメロンが有名な果物専門店と、併設された果物が楽しめる飲食店。",
  361. "[卯]紀伊國屋書店。大正16年に創業した、文士たちが集うサロンのような大型書店。",
  362. "[辰]新宿御苑。宮内省が管理する皇室のための庭園。封印具の保管庫である浄玻璃ノ宮がある。",
  363. "[巳]明治神宮。明治天皇と昭憲皇太后を祭神とした神社。境内は厳かな雰囲気に満ちている。",
  364. ]],
  365. [4..5, [
  366. "[午]新宿駅。多摩や小田原からの玄関口となる駅。1日あたりの乗降客数は日本一。",
  367. "[未]酩酊横丁。長屋が連なる路地に、200軒以上もの居酒屋やバーがひしめいている。",
  368. "[申]歌楽騒戯通り。関東大震災後に作られた真新しい建物がひしめく歓楽街。",
  369. "[酉]淀橋浄水場。コレラ流行後に、水道を近代化させるために作られた浄水場。",
  370. "[戌]新宿大通り。急速な発展を遂げた新宿のメイン通り。",
  371. "[亥]ほたる屋。妖狐と妖狸が経営している衣料品専門の百貨店。",
  372. ]],
  373. [6..6, Array.new(6, "午~亥まで任意の十二支を選択する。")],
  374. ]
  375. ),
  376. }.freeze
  377. 1 register_prefix('\d*AB', TABLES.keys)
  378. end
  379. end
  380. end

lib/bcdice/game_system/BBN.rb

96.77% lines covered

92.0% branches covered

62 relevant lines. 60 lines covered and 2 lines missed.
25 total branches, 23 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BBN < Base
  5. # ダイスボットで使用するコマンドを配列で列挙する
  6. 1 register_prefix('\d+BN')
  7. 1 ID = 'BBN'
  8. 1 NAME = 'BBNTRPG'
  9. 1 SORT_KEY = 'ひいひいえぬTRPG'
  10. 1 HELP_MESSAGE = <<~MESSAGETEXT
  11. ・判定(xBN±y>=z[c,f])
  12.  xD6の判定。クリティカル、ファンブルの自動判定を行います。
  13.  1Dのクリティカル値とファンブル値は1。2Dのクリティカル値とファンブル値は2。
  14.  nDのクリティカル値とファンブル値は n/2 の切り上げ。
  15.  クリティカルとファンブルが同時に発生した場合、クリティカルを優先。
  16.  x:xに振るダイス数を入力。
  17.  y:yに修正値を入力。省略可能。
  18. z:zに目標値を入力。省略可能。
  19. c:クリティカルに必要なダイス目「6」の数の増減。省略可能。
  20. f:ファンブルに必要なダイス目「1」の数の増減。省略可能。
  21.  例) 3BN+4 3BN>=8 3BN+1>=10[-1] 3BN+1>=10[,1] 3BN+1>=10[1,1]
  22. MESSAGETEXT
  23. 1 def eval_game_system_specific_command(command)
  24. 29 else: 29 then: 0 unless parse(command)
  25. return nil
  26. end
  27. # ダイスロール
  28. 29 dice_list = @randomizer.roll_barabara(@roll_times, 6)
  29. 29 dice = dice_list.sum()
  30. 29 dice_str = dice_list.join(",")
  31. 29 total = dice + @modify
  32. # 出力文の生成
  33. sequence = [
  34. 29 "(#{command})",
  35. "#{dice}[#{dice_str}]#{@modify_str}",
  36. total
  37. ]
  38. # クリティカルとファンブルが同時に発生した時にはクリティカルが優先
  39. 29 then: 13 if critical_?(dice_list)
  40. 13 else: 16 sequence.push("クリティカル!", *additional_roll(dice_list.count(6), total))
  41. 16 then: 8 elsif fumble_?(dice_list)
  42. 8 else: 8 sequence.push("ファンブル!")
  43. 8 then: 2 else: 6 elsif @difficulty
  44. 2 then: 1 else: 1 sequence.push(total >= @difficulty ? "成功" : "失敗")
  45. end
  46. 29 return sequence.join(" > ")
  47. end
  48. 1 private
  49. # コマンド文字列をパースする
  50. #
  51. # @param command [String] コマンド
  52. # @return [Boolean] パースに成功したか
  53. 1 def parse(command)
  54. 29 m = /^(\d+)BN([+-]\d+)?(>=(([+-]?\d+)))?(\[([+-]?\d+)?(,([+-]?\d+))?\])?/.match(command)
  55. 29 else: 29 then: 0 unless m
  56. return false
  57. end
  58. 29 @roll_times = m[1].to_i
  59. 29 @modify_str = m[2] || ''
  60. 29 @modify = m[2].to_i
  61. 29 then: 5 else: 24 @difficulty = m[4]&.to_i
  62. 29 base = critical_base(@roll_times)
  63. 29 @critical = base + m[7].to_i
  64. 29 @fumble = base + m[9].to_i
  65. 29 return true
  66. end
  67. # 振るダイスの数からクリティカルとファンブルの基本値を算出する
  68. #
  69. # @param roll_times [Integer] 振るダイスの数
  70. # @return [Integer] クリティカルの値
  71. 1 def critical_base(roll_times)
  72. 29 case roll_times
  73. when: 14 when 1, 2
  74. 14 roll_times
  75. else: 15 else
  76. 15 (roll_times.to_f / 2).ceil
  77. end
  78. end
  79. # @return [Boolean] クリティカルか
  80. 1 def critical_?(dice_list)
  81. 29 dice_list.count(6) >= @critical
  82. end
  83. # @return [Boolean] ファンブルか
  84. 1 def fumble_?(dice_list)
  85. 16 dice_list.count(1) >= @fumble
  86. end
  87. # クリティカルの追加ロールをする
  88. # 追加ロールで6が出た場合、さらに追加ロールが行われる
  89. #
  90. # @param additional_dice [Integer] クリティカルによる追加のダイス数
  91. # @param total [Integer] 現在の合計値
  92. # @return [Array<String>]
  93. 1 def additional_roll(additional_dice, total)
  94. 13 sequence = []
  95. 13 reroll_count = 0
  96. # 追加クリティカルは無限ループしうるので、10回に制限
  97. 13 body: 27 while additional_dice > 0 && reroll_count < 10
  98. 27 reroll_count += 1
  99. 27 dice_list = @randomizer.roll_barabara(additional_dice, 6)
  100. 27 dice_total = dice_list.sum()
  101. 27 dice_str = dice_list.join(",")
  102. 27 additional_dice = dice_list.count(6)
  103. 27 sequence.push("#{total}+#{dice_total}[#{dice_str}]")
  104. 27 then: 15 else: 12 sequence.push("追加クリティカル!") if additional_dice > 0
  105. 27 total += dice_total
  106. end
  107. 13 then: 1 else: 12 if additional_dice > 0
  108. 1 sequence.push("無限ループ防止のため中断")
  109. end
  110. 13 sequence.push total
  111. 13 then: 2 else: 11 if @difficulty
  112. 2 then: 1 else: 1 sequence.push(total >= @difficulty ? "成功" : "失敗")
  113. end
  114. 13 return sequence
  115. end
  116. end
  117. end
  118. end

lib/bcdice/game_system/BadLife.rb

100.0% lines covered

100.0% branches covered

71 relevant lines. 71 lines covered and 0 lines missed.
41 total branches, 41 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BadLife < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'BadLife'
  7. # ゲームシステム名
  8. 1 NAME = 'バッドライフ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'はつとらいふ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定:nBADm[±a][Cb±c][Fd±e][@X±f][!OP]  []内のコマンドは省略可。
  14. ・BADコマンドは「BL」コマンドで代用可。
  15. ・博徒は「GL」コマンドで〈波乱万丈〉の効果を適用。
  16. 「n」で振るダイス数、「m」で特性値、「±a」で達成値への修正値、
  17. 「Cb±c」でクリティカル値への修正、「Fd±e」でファンブル値への修正、
  18. 「@X」で目標難易度を指定。
  19. 「±a」「Cb±c」「Fd±e」[@X±f]部分は「4+1-3」などの複数回指定可。
  20. 「!OP」部分で、一部のスキルやガジェットの追加効果を指定可。
  21. 使用可能なコマンドは以下の通り。順不同、複数同時使用も可。
  22. A:〈先見の明〉  H:[重撃]
  23. 【書式例】
  24. BAD → 1ダイスで達成値を表示。
  25. 3BAD10+2-1 → 3ダイスで修正+11の達成値を表示。
  26. BL8@15 → 1ダイスで修正+8、難易度15の判定。
  27. 2BL8C-1F1@15 → 2ダイスで修正+8、C値-1、F値+1、難易度15の判定。
  28. GL6@20 → 1ダイスで修正+6、難易度20の判定。〈波乱万丈〉の効果。
  29. GL6@20!HA → 上記に加えて〈先見の明〉[重撃]の効果。
  30. ・コードネーム表
  31. 怪盗:TRN   闇医者:DRN  博徒:GRN
  32. 殺シ屋:KRN  業師:SRN   遊ビ人:BRN
  33. ・スキル表:SKL
  34. MESSAGETEXT
  35. 1 register_prefix('\d?(BAD|BL|GL)', '[TDGKSB]RN', 'SKL')
  36. 1 def eval_game_system_specific_command(command)
  37. 78 judgeDice(command) || roll_tables(command, TABLES)
  38. end
  39. 1 def judgeDice(command)
  40. 78 else: 63 then: 15 unless (m = /(\d+)?(BAD|BL|GL)([-+\d]*)((C|F)([-+\d]*)?)?((C|F)([-+\d]*))?(@([-+\d]*))?(!(\D*))?/i.match(command))
  41. 15 return nil
  42. end
  43. 63 diceCount = (m[1] || 1).to_i
  44. 63 critical = 20
  45. 63 fumble = 1
  46. 63 isStormy = (m[2] == 'GL') # 波乱万丈
  47. 63 then: 7 else: 56 if isStormy
  48. 7 critical -= 3
  49. 7 fumble += 1
  50. end
  51. 63 modify = get_value(m[3])
  52. 63 critical, fumble = get_critival_fumble(critical, fumble, m[5], m[6])
  53. 63 critical, fumble = get_critival_fumble(critical, fumble, m[8], m[9])
  54. 63 target = get_value(m[11])
  55. 63 optionalText = m[13] || ''
  56. 63 return checkRoll(diceCount, modify, critical, fumble, target, isStormy, optionalText)
  57. end
  58. 1 def get_critival_fumble(critical, fumble, marker, text)
  59. 126 else: 91 case marker
  60. when: 18 when 'C'
  61. 18 critical += get_value(text)
  62. when: 17 when 'F'
  63. 17 fumble += get_value(text)
  64. end
  65. 126 return critical, fumble
  66. end
  67. 1 def checkRoll(diceCount, modify, critical, fumble, target, isStormy, optionalText)
  68. 63 isAnticipation = optionalText.include?('A') # 先見の明
  69. 63 isHeavyAttack = optionalText.include?('H') # 重撃
  70. 63 dice_list = @randomizer.roll_barabara(diceCount, 20)
  71. 63 diceText = dice_list.join(",")
  72. 63 diceMax = dice_list.max
  73. 63 then: 5 else: 58 diceMax = 5 if isHeavyAttack && diceMax <= 5 # 重撃
  74. 63 isCritical = (diceMax >= critical)
  75. 63 isFumble = (diceMax <= fumble)
  76. 63 then: 14 else: 49 diceMax = 20 if isCritical # クリティカル
  77. 63 total = diceMax + modify
  78. 63 then: 8 else: 55 total += 5 if isAnticipation && diceMax <= 7 # 先見の明
  79. 63 then: 12 else: 51 total = 0 if isFumble # ファンブル
  80. 63 result = "#{diceCount}D20\(C:#{critical},F:#{fumble}\) > "
  81. 63 result += "#{diceMax}\[#{diceText}\]"
  82. 63 then: 34 else: 29 result += "\+" if modify > 0
  83. 63 then: 35 else: 28 result += modify.to_s if modify != 0
  84. 63 then: 8 else: 55 result += "\+5" if isAnticipation && diceMax <= 7 # 先見の明
  85. 63 result += " > 達成値:#{total}"
  86. 63 then: 11 if target > 0
  87. 11 success = total - target
  88. 11 result += ">=#{target} 成功度:#{success} > "
  89. 11 then: 2 if isCritical
  90. 2 else: 9 result += "成功(クリティカル)"
  91. 9 then: 5 elsif total >= target
  92. 5 result += "成功"
  93. else: 4 else
  94. 4 result += "失敗"
  95. 4 then: 1 else: 3 result += "(ファンブル)" if isFumble
  96. end
  97. else: 52 else
  98. 52 then: 12 else: 40 result += " クリティカル" if isCritical
  99. 52 then: 11 else: 41 result += " ファンブル" if isFumble
  100. end
  101. 63 skillText = ""
  102. 63 then: 7 else: 56 skillText += "〈波乱万丈〉" if isStormy
  103. 63 then: 11 else: 52 skillText += "〈先見の明〉" if isAnticipation
  104. 63 then: 9 else: 54 skillText += "[重撃]" if isHeavyAttack
  105. 63 then: 22 else: 41 result += " #{skillText}" if skillText != ""
  106. 63 return result
  107. end
  108. 1 def get_value(text)
  109. 161 text ||= ""
  110. 161 return ArithmeticEvaluator.eval(text)
  111. end
  112. TABLES = {
  113. 1 "SKL" => DiceTable::Table.new(
  114. "スキル表",
  115. "1D100",
  116. [
  117. "一撃離脱",
  118. "一撃離脱",
  119. "チェイサー",
  120. "チェイサー",
  121. "影の外套",
  122. "影の外套",
  123. "二段ジャンプ",
  124. "二段ジャンプ",
  125. "韋駄天",
  126. "韋駄天",
  127. "手練",
  128. "手練",
  129. "ハニーテイスト",
  130. "ハニーテイスト",
  131. "先見の明",
  132. "先見の明",
  133. "ベテラン",
  134. "ベテラン",
  135. "応急手当",
  136. "応急手当",
  137. "セラピー",
  138. "セラピー",
  139. "緊急治療",
  140. "緊急治療",
  141. "ゴールドディガー",
  142. "ゴールドディガー",
  143. "デイリーミッション",
  144. "デイリーミッション",
  145. "見切り",
  146. "見切り",
  147. "鷹の目",
  148. "鷹の目",
  149. "しびれ罠",
  150. "しびれ罠",
  151. "大逆転",
  152. "大逆転",
  153. "武器習熟:○○",
  154. "武器習熟:○○",
  155. "百発百中",
  156. "百発百中",
  157. "屈強な肉体",
  158. "屈強な肉体",
  159. "二刀流",
  160. "二刀流",
  161. "クイックリカバリー",
  162. "クイックリカバリー",
  163. "体験主義",
  164. "体験主義",
  165. "破釜沈船",
  166. "破釜沈船",
  167. "想定の範囲内",
  168. "想定の範囲内",
  169. "セカンドチャンス",
  170. "セカンドチャンス",
  171. "優秀な子分",
  172. "優秀な子分",
  173. "時間管理術",
  174. "時間管理術",
  175. "連撃術",
  176. "連撃術",
  177. "罵詈雑言",
  178. "罵詈雑言",
  179. "ケセラセラ",
  180. "ケセラセラ",
  181. "ダンス&ミュージック",
  182. "ダンス&ミュージック",
  183. "フェイント",
  184. "フェイント",
  185. "ヘイトコントロール",
  186. "ヘイトコントロール",
  187. "惜別",
  188. "惜別",
  189. "戦闘マシーン",
  190. "戦闘マシーン",
  191. "戦闘マシーン",
  192. "名医",
  193. "名医",
  194. "名医",
  195. "忍者",
  196. "忍者",
  197. "忍者",
  198. "観察眼",
  199. "観察眼",
  200. "観察眼",
  201. "クレバー",
  202. "クレバー",
  203. "クレバー",
  204. "フェイスマン",
  205. "フェイスマン",
  206. "フェイスマン",
  207. "スポーツマン",
  208. "スポーツマン",
  209. "スポーツマン",
  210. "不屈",
  211. "不屈",
  212. "不屈",
  213. "慎重",
  214. "慎重",
  215. "慎重",
  216. "この表を2回振る",
  217. ]
  218. ),
  219. "TRN" => DiceTable::Table.new(
  220. "怪盗コードネーム表",
  221. "1D20",
  222. [
  223. "フォックス",
  224. "フォックス",
  225. "ラット",
  226. "ラット",
  227. "キャット",
  228. "キャット",
  229. "タイガー",
  230. "タイガー",
  231. "シャーク",
  232. "シャーク",
  233. "コンドル",
  234. "コンドル",
  235. "スパイダー",
  236. "スパイダー",
  237. "ウルフ",
  238. "ウルフ",
  239. "コヨーテ",
  240. "コヨーテ",
  241. "ジャガー",
  242. "ジャガー",
  243. ]
  244. ),
  245. "DRN" => DiceTable::Table.new(
  246. "闇医者コードネーム表",
  247. "1D20",
  248. [
  249. "キャンサー",
  250. "キャンサー",
  251. "ヘッドエイク",
  252. "ヘッドエイク",
  253. "ブラッド",
  254. "ブラッド",
  255. "ウーンズ",
  256. "ウーンズ",
  257. "ポイズン",
  258. "ポイズン",
  259. "ペイン",
  260. "ペイン",
  261. "スリープ",
  262. "スリープ",
  263. "キュア",
  264. "キュア",
  265. "デス",
  266. "デス",
  267. "リーンカーネイション",
  268. "リーンカーネイション",
  269. ]
  270. ),
  271. "GRN" => DiceTable::Table.new(
  272. "博徒コードネーム表",
  273. "1D20",
  274. [
  275. "リトルダイス",
  276. "リトルダイス",
  277. "プラチナム",
  278. "プラチナム",
  279. "プレジデント",
  280. "プレジデント",
  281. "ドリーム",
  282. "ドリーム",
  283. "アクシデント",
  284. "アクシデント",
  285. "グリード",
  286. "グリード",
  287. "フォーチュン",
  288. "フォーチュン",
  289. "ミラクル",
  290. "ミラクル",
  291. "ホープ",
  292. "ホープ",
  293. "ビッグヒット",
  294. "ビッグヒット",
  295. ]
  296. ),
  297. "KRN" => DiceTable::Table.new(
  298. "殺シ屋コードネーム表",
  299. "1D20",
  300. [
  301. "ハンマー",
  302. "ハンマー",
  303. "アロー",
  304. "アロー",
  305. "ボマー",
  306. "ボマー",
  307. "キャノン",
  308. "キャノン",
  309. "ブレード",
  310. "ブレード",
  311. "スティング",
  312. "スティング",
  313. "ガロット",
  314. "ガロット",
  315. "パイルバンカー",
  316. "パイルバンカー",
  317. "レイザー",
  318. "レイザー",
  319. "カタナ",
  320. "カタナ",
  321. ]
  322. ),
  323. "SRN" => DiceTable::Table.new(
  324. "業師コードネーム表",
  325. "1D20",
  326. [
  327. "ローズ",
  328. "ローズ",
  329. "サクラ",
  330. "サクラ",
  331. "ライラック",
  332. "ライラック",
  333. "ダンデライオン",
  334. "ダンデライオン",
  335. "フリージア",
  336. "フリージア",
  337. "カクタス",
  338. "カクタス",
  339. "ロータス",
  340. "ロータス",
  341. "リリィ",
  342. "リリィ",
  343. "ラフレシア",
  344. "ラフレシア",
  345. "ヒヤシンス",
  346. "ヒヤシンス",
  347. ]
  348. ),
  349. "BRN" => DiceTable::Table.new(
  350. "遊ビ人コードネーム表",
  351. "1D20",
  352. [
  353. "モノポリー",
  354. "モノポリー",
  355. "ブリッジ",
  356. "ブリッジ",
  357. "チェッカー",
  358. "チェッカー",
  359. "アクワイア",
  360. "アクワイア",
  361. "ジャンケン",
  362. "ジャンケン",
  363. "トランプ",
  364. "トランプ",
  365. "ケイドロ",
  366. "ケイドロ",
  367. "パンデミック",
  368. "パンデミック",
  369. "スゴロク",
  370. "スゴロク",
  371. "キャベツカンテイ",
  372. "キャベツカンテイ",
  373. ]
  374. ),
  375. }.freeze
  376. end
  377. end
  378. end

lib/bcdice/game_system/Bakenokawa.rb

100.0% lines covered

100.0% branches covered

42 relevant lines. 42 lines covered and 0 lines missed.
8 total branches, 8 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/dice_table/table'
  3. 1 require 'bcdice/dice_table/d66_table'
  4. 1 require 'bcdice/arithmetic'
  5. 1 require 'bcdice/command/parser'
  6. 1 module BCDice
  7. 1 module GameSystem
  8. 1 class Bakenokawa < Base
  9. # ゲームシステムの識別子
  10. 1 ID = 'Bakenokawa'
  11. # ゲームシステム名
  12. 1 NAME = 'バケノカワ'
  13. # ゲームシステム名の読みがな
  14. #
  15. # 「ゲームシステム名の読みがなの設定方法」(docs/dicebot_sort_key.md)を参考にして
  16. # 設定してください
  17. 1 SORT_KEY = 'はけのかわ'
  18. # ダイスボットの使い方
  19. 1 HELP_MESSAGE = <<~MESSAGETEXT
  20. ・行為判定
  21. xBKy@z
  22. x:振るダイスの数(省略可、省略した場合は2)
  23. y:振るダイスの面数
  24. z:スペシャル値(@ごと省略可、省略した場合は12)
  25. (例)BK10
  26.    4BK6
  27.    2BK6@10
  28. ・各種表
  29. 今の関係表 NRT
  30. カイブツ時代からの因縁表 KKT
  31. 調査演出表
  32. カイブツ RTK
  33. バケノカワ RTB
  34. コラボテーマ表
  35. カイブツ CTK
  36. バケノカワ CTB
  37. ファンブル表 FT
  38. MESSAGETEXT
  39. 1 def initialize(command)
  40. 69 super(command)
  41. 69 @sort_barabara_dice = true
  42. 69 @d66_sort_type = D66SortType::ASC
  43. end
  44. 1 def eval_game_system_specific_command(command)
  45. 69 return check_action(command) || roll_tables(command, TABLES)
  46. end
  47. 1 def check_action(command)
  48. 69 parser = Command::Parser.new("BK", round_type: RoundType::FLOOR).enable_critical.enable_prefix_number.has_suffix_number
  49. 69 parsed = parser.parse(command)
  50. 69 then: 14 else: 55 return nil if parsed.nil?
  51. 55 target = 4
  52. 55 dice_cnt = parsed.prefix_number || 2
  53. 55 dice_faces = parsed.suffix_number
  54. 55 special_target = parsed.critical || 12
  55. 55 debug("dice_faces", dice_faces)
  56. 55 debug("dice_cnt", dice_cnt)
  57. 55 debug("special_target", special_target)
  58. 55 dice_arr = @randomizer.roll_barabara(dice_cnt, dice_faces).sort
  59. 55 dice_str = dice_arr.join(",")
  60. 55 dice_sum = dice_arr.sum
  61. 55 has_special = dice_sum >= special_target
  62. 55 has_fumble = dice_sum <= 2
  63. 183 result = dice_arr.count { |x| x >= target } >= 1
  64. 55 Result.new.tap do |r|
  65. 55 then: 36 else: 19 then: 21 else: 34 then: 8 else: 47 r.text = "(#{dice_cnt}B#{dice_faces}>=#{target}) > [#{dice_str}] > #{dice_sum} > #{result ? '成功' : '失敗'}#{has_special ? '(スペシャル)' : ''}#{has_fumble ? '(ファンブル)' : ''}"
  66. 55 r.critical = has_special
  67. 55 r.fumble = has_fumble
  68. 55 r.success = result
  69. 55 r.failure = !r.success?
  70. end
  71. end
  72. TABLES = {
  73. 1 'NRT' => DiceTable::D66Table.new(
  74. '今の関係表',
  75. D66SortType::ASC,
  76. {
  77. 11 => 'バケノカワ同士が親戚だった',
  78. 12 => '仲のいい職場の同僚',
  79. 13 => '仕事のことで助けてもらったことがある',
  80. 14 => '人間社会のことを教え合っている',
  81. 15 => '施設同士がよくコラボする',
  82. 16 => '街のお店に二人で出かける仲',
  83. 22 => 'どうにもウマが合わずに喧嘩ばかりしている',
  84. 23 => 'そのバケノカワを羨ましいと思っていた',
  85. 24 => 'バケノカワに関する苦労を聞いたことがある',
  86. 25 => 'バケノカワとしての生活圏が近い',
  87. 26 => 'バケノカワ同士が知り合いだった',
  88. 33 => 'あんな人間になりたいと憧れを覚えた',
  89. 34 => '友人として色々な悩みを共に解決してきた',
  90. 35 => '放っておけないところがあると思っている',
  91. 36 => 'いつも迷惑をかけて悪いと思っている',
  92. 44 => '毎朝挨拶をするようなご近所さん/寮の部屋が隣',
  93. 45 => '何か悩んでいそうな顔が気になった',
  94. 46 => '何かと仕事関係で助けてもらい、世話になっている',
  95. 55 => '立ち振る舞いが人間らしくて羨ましい',
  96. 56 => 'ワンダーランドでの振る舞いや仕事ぶりに一目置いている',
  97. 66 => 'そのバケノカワを見ると懐かしさを覚える',
  98. }
  99. ),
  100. 'KKT' => DiceTable::D66Table.new(
  101. 'カイブツ時代からの因縁表',
  102. D66SortType::ASC,
  103. {
  104. 11 => '一緒の牢獄に捕まっていたことがある',
  105. 12 => '地下の国で一緒に遊んでいたことがある',
  106. 13 => '地上に出て人間を楽しませる夢を語り合った',
  107. 14 => '一緒に人間社会を学ぶ訓練を受けた',
  108. 15 => '生まれた時からずっと一緒だった',
  109. 16 => '時々喧嘩をし合うような仲だった',
  110. 22 => '幼少期に育ててもらった恩がある',
  111. 23 => '昔助けてもらった時の借りがある',
  112. 24 => '思い出せないぐらい昔に、助けてもらった……気がする',
  113. 25 => '一緒に地上で人間を楽しませようと約束した',
  114. 26 => '人間に対する憧れを語った',
  115. 33 => 'カイブツ時代、一方的に憧れを抱いていた',
  116. 34 => '人間のまね事を一緒にしていた',
  117. 35 => '少しの間、一緒に暮らしていたことがある',
  118. 36 => '一緒にお茶会をした仲',
  119. 44 => '同じ親のもとで育った',
  120. 45 => 'カイブツ時代に貸しがあって、まだ返してもらってない',
  121. 46 => '何かと競い合う、ライバル同士だった',
  122. 55 => '戦いを挑み、ボコボコにされた',
  123. 56 => '一緒に退屈を紛らわすために色々悪だくみしていた',
  124. 66 => 'バケノカワを貰った後にやりたいことを語ってもらった覚えがある',
  125. }
  126. ),
  127. 'RTK' => DiceTable::Table.new(
  128. '調査演出表 カイブツ',
  129. '1D10',
  130. [
  131. 'カイブツとして街に潜み、チェインNPCの周りを調べて回った',
  132. 'カイブツとしての力を使い、チェインNPCを尾行して好みを調べた',
  133. '人間には潜入できないルートを使って、チェインNPCの周りを調べた',
  134. '人間として調べてみようとしたが、カイブツとしての特徴が出て困った',
  135. 'カイブツとしての特徴を調査に活かし、調べ上げた',
  136. '魔法の鏡に問いかけて、答えを貰った',
  137. 'チェインNPCの痕跡から、魔法の力を使って過去を辿った',
  138. '仲間のカイブツたちと一緒に、街に繰り出してドタバタ劇を繰り広げながら情報を集めた',
  139. '小さなカイブツたちに、気付かれないようにチェインNPCを調べてもらった',
  140. '魔女のカイブツに頼んで、調査に便利な薬を作ってもらった,'
  141. ]
  142. ),
  143. 'RTB' => DiceTable::Table.new(
  144. '調査演出表 バケノカワ',
  145. '1D10',
  146. [
  147. '人間の友人を頼ってチェインNPCの噂話を聞く',
  148. '人間の街に行ってチェインNPCのことを聞いて回る',
  149. 'チェインPCに話を聞いて、その子の特徴から好みを推察する',
  150. 'チェインPCと一緒に、チェインNPCの周囲を聞き込みして回った',
  151. '人間として、情報通の人間が集まる場所に向かい、そこでいろいろな話を聞いて回った',
  152. 'ネットを利用して、チェインNPCの痕跡がないか調べてみた',
  153. 'チェインNPCがよく行く場所を掴み、そこで情報収集をした',
  154. '実は、チェインNPCは自分のバケノカワとして会ったことがあり、そのときのことを思い出した',
  155. '実は、チェインNPCはお客様として自分の担当施設に来たことがあり、そのときの印象を思い出した',
  156. ]
  157. ),
  158. 'CTK' => DiceTable::D66Table.new(
  159. 'コラボテーマ表 カイブツ',
  160. D66SortType::ASC,
  161. {
  162. 11 => '自分とコラボ相手の「カイブツとしての姿」を使ったド派手なコラボ',
  163. 12 => '自分の特徴を使ったコラボ',
  164. 13 => 'コラボ相手の特徴を使ったコラボ',
  165. 14 => '自分とコラボ相手の特徴を活かすコラボ',
  166. 15 => '自分の施設とコラボ相手の特徴を合わせたコラボ',
  167. 16 => 'コラボ相手の施設と自分の特徴を合わせたコラボ',
  168. 22 => '自分とコラボ相手の「カイブツとしての力」を使ったコラボ',
  169. 23 => '自分とコラボ相手のパビリオンを活かすコラボ',
  170. 24 => '自分のカイブツとしての力を使ったコラボ',
  171. 25 => '相手のカイブツとしての力を使ったコラボ',
  172. 26 => '自分がカイブツとして優れているところを、コラボ相手に聞いてヒントにする',
  173. 33 => 'カイブツとしての姿をキャラクターグッズとして売り出すコラボ',
  174. 34 => '魔法の力を演出に使った、キラキラのコラボ',
  175. 35 => '魔法の道具を使った、お客様を驚かせるようなコラボ',
  176. 36 => '童話の世界をくっつけて、ちぐはぐな感じを楽しんでもらう',
  177. 44 => 'パビリオンの仲間たちを集めたステージを開催',
  178. 45 => 'カイブツとしての姿をあえて晒し、それを「演出」に組み込む',
  179. 46 => '自分たちの力を「演出」として使ったコラボ',
  180. 55 => '魔法の力がかかったお土産を持たせるコラボ',
  181. 56 => '不思議な演出がいっぱいのコラボ',
  182. 66 => '自分たち以外のカイブツも呼んだ、賑やかなコラボ',
  183. }
  184. ),
  185. 'CTB' => DiceTable::D66Table.new(
  186. 'コラボテーマ表 バケノカワ',
  187. D66SortType::ASC,
  188. {
  189. 11 => 'バケノカワとして生活するうちに覚えた、「楽しかったこと」をやってみる',
  190. 12 => 'コラボ相手の施設におじゃまするコラボ',
  191. 13 => '自分の施設にコラボ相手を呼ぶ',
  192. 14 => '自分とコラボ相手の施設にお土産を用意する',
  193. 15 => 'コラボ相手の施設の要素を使う',
  194. 16 => '自分の施設の要素をコラボ相手の施設に贈る',
  195. 22 => 'バケノカワ生活の中で気付いた、「人間は面白い」と思えたことをやる',
  196. 23 => '自分とコラボ相手の技能で園全体を盛り上げる',
  197. 24 => '自分の技能をコラボ相手の施設に活かす',
  198. 25 => 'パートナーの技能を自分の施設に活かす',
  199. 26 => '自分のカバーパーソナルを活かすコラボ',
  200. 33 => '自分だけではできないことをコラボ相手と相談する',
  201. 34 => 'パートナーのカバーパーソナルを活かすコラボ',
  202. 35 => '二つの施設を合わせたような施設を限定オープン',
  203. 36 => 'お客様の笑顔を思い出し、そうなるように二人で努力する',
  204. 44 => '二つの施設を繋げる園内バスを用意する',
  205. 45 => 'お客様に楽しんでもらえる演出を二人で考える',
  206. 46 => 'お客様が好みそうなお土産を二人で考える',
  207. 55 => '人間の友達に、「何が楽しいのか」を改めて聞く',
  208. 56 => 'バケノカワの伝手を使って、人間の友達に話を聞く',
  209. 66 => 'ワンダーランドのみんなに手伝ってもらう豪華なコラボ',
  210. }
  211. ),
  212. 'FT' => DiceTable::Table.new(
  213. 'ファンブル表',
  214. '1D6',
  215. [
  216. '「あれ?”自分”は一体何者だったかな?」カバーパーソナルを1つ選んで失う',
  217. 'ふとした瞬間に、楽しい感情に対して懐疑的になってしまう。ワンダートークンを1個選んで失う',
  218. 'せっかく用意した道具を壊してしまう。セットしていたサプライズカードを1枚選んで破棄する',
  219. 'バケノカワの記憶が思い出される。カバーパーソナルとそれに付随するパーソナル技能を1つずつ獲得する',
  220. 'カイブツとしての自分が前面に出てしまう。次に行う判定の間、すべての技能を修得していないものとして扱う',
  221. '失敗してしまったが、それがお客様にウケた。ワンダートークンを1個獲得する',
  222. ]
  223. ),
  224. }.freeze
  225. # ダイスボットで使用するコマンドを配列で列挙する
  226. 1 register_prefix('\d*BK', TABLES.keys)
  227. end
  228. end
  229. end

lib/bcdice/game_system/BarnaKronika.rb

100.0% lines covered

94.12% branches covered

98 relevant lines. 98 lines covered and 0 lines missed.
34 total branches, 32 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BarnaKronika < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'BarnaKronika'
  7. # ゲームシステム名
  8. 1 NAME = 'バルナ・クロニカ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'はるなくろにか'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・通常判定 nBK
  14.  ダイス数nで判定ロールを行います。
  15.  セット数が1以上の時はセット数も表示します。
  16. ・攻撃判定 nBA
  17.  ダイス数nで判定ロールを行い、攻撃値と命中部位も表示します。
  18. ・クリティカルコール nBKCt nBACt
  19.  判定コマンドの後ろに「Ct」を付けるとクリティカルコールです。
  20.  ダイス数n,コール数tで判定ロールを行います。
  21.  ダイス数nで判定ロールを行います。
  22.  セット数が1以上の時はセット数も表示し、攻撃判定の場合は命中部位も表示します。
  23. INFO_MESSAGE_TEXT
  24. 1 register_prefix('\d+BK', '\d+BA', '\d+BKC', '\d+BAC', '\d+R6')
  25. 1 def initialize(command)
  26. 120 super(command)
  27. 120 @sort_add_dice = true
  28. 120 @sort_barabara_dice = true
  29. end
  30. 1 def replace_text(string)
  31. 150 string = string.gsub(/(\d+)BKC(\d)/) { "#{Regexp.last_match(1)}R6[0,#{Regexp.last_match(2)}]" }
  32. 150 string = string.gsub(/(\d+)BAC(\d)/) { "#{Regexp.last_match(1)}R6[1,#{Regexp.last_match(2)}]" }
  33. 150 string = string.gsub(/(\d+)BK/) { "#{Regexp.last_match(1)}R6[0,0]" }
  34. 150 string = string.gsub(/(\d+)BA/) { "#{Regexp.last_match(1)}R6[1,0]" }
  35. 120 return string
  36. end
  37. 1 def eval_game_system_specific_command(string)
  38. 120 string = replace_text(string)
  39. 120 else: 120 then: 0 return nil unless /(^|\s)S?((\d+)[rR]6(\[([,\d]+)\])?)(\s|$)/i =~ string
  40. 120 string = Regexp.last_match(2)
  41. 120 option = Regexp.last_match(5)
  42. 120 dice_n = Regexp.last_match(3)
  43. 120 dice_n ||= 1
  44. 120 @isBattleMode = false # 0=判定モード, 1=戦闘モード
  45. 120 criticalCallDice = 0 # 0=通常, 1〜6=クリティカルコール
  46. 120 then: 120 else: 0 if option
  47. 120 battleModeText, criticalCallDice = option.split(",").map(&:to_i)
  48. 120 @isBattleMode = (battleModeText == 1)
  49. end
  50. 120 debug("@isBattleMode", @isBattleMode)
  51. 120 dice_str, suc, set, at_str = roll_barna_kronika(dice_n, criticalCallDice)
  52. 120 output = "(#{string}) > [#{dice_str}] > "
  53. 120 then: 60 if @isBattleMode
  54. 60 output += at_str
  55. else: 60 else
  56. 60 debug("suc", suc)
  57. 60 then: 31 if suc > 1
  58. 31 output += "成功数#{suc}"
  59. else: 29 else
  60. 29 output += "失敗"
  61. end
  62. 60 debug("set", set)
  63. 60 then: 31 else: 29 output += ",セット#{set}" if set > 0
  64. end
  65. 120 return output
  66. end
  67. 1 def roll_barna_kronika(dice_n, criticalCallDice)
  68. 120 dice_n = dice_n.to_i
  69. 120 output = ''
  70. 120 suc = 0
  71. 120 set = 0
  72. 120 at_str = ''
  73. 120 diceCountList = [0, 0, 0, 0, 0, 0]
  74. 120 dice_n.times do |_i|
  75. 450 index = @randomizer.roll_index(6)
  76. 450 diceCountList[index] += 1
  77. 450 then: 208 else: 242 if diceCountList[index] > suc
  78. 208 suc = diceCountList[index]
  79. end
  80. end
  81. 120 6.times do |i|
  82. 720 diceCount = diceCountList[i]
  83. 720 then: 398 else: 322 next if diceCount == 0
  84. 322 diceCount.times do |_j|
  85. 450 output += "#{i + 1},"
  86. end
  87. 322 then: 12 if isCriticalCall(i, criticalCallDice)
  88. 12 debug("isCriticalCall")
  89. 12 else: 310 at_str += getAttackStringWhenCriticalCall(i, diceCount)
  90. 310 then: 24 else: 286 elsif isNomalAttack(criticalCallDice, diceCount)
  91. 24 debug("isNomalAttack")
  92. 24 at_str += getAttackStringWhenNomal(i, diceCount)
  93. end
  94. 322 then: 100 else: 222 set += 1 if diceCount > 1
  95. end
  96. 120 then: 60 else: 60 if criticalCallDice != 0
  97. 60 c_cnt = diceCountList[criticalCallDice - 1]
  98. 60 suc = c_cnt * 2
  99. 60 then: 29 if c_cnt != 0
  100. 29 set = 1
  101. else: 31 else
  102. 31 set = 0
  103. end
  104. end
  105. 120 then: 33 else: 87 if @isBattleMode && (suc < 2)
  106. 33 at_str = "失敗"
  107. end
  108. 120 output = output.sub(/,$/, '')
  109. 120 at_str = at_str.sub(/,$/, '')
  110. 120 return output, suc, set, at_str
  111. end
  112. 1 def isCriticalCall(index, criticalCallDice)
  113. 322 else: 152 then: 170 return false unless @isBattleMode
  114. 152 then: 77 else: 75 return false if criticalCallDice == 0
  115. 75 return (criticalCallDice == (index + 1))
  116. end
  117. 1 def isNomalAttack(criticalCallDice, diceCount)
  118. 310 else: 140 then: 170 return false unless @isBattleMode
  119. 140 then: 63 else: 77 return false if criticalCallDice != 0
  120. 77 return (diceCount > 1)
  121. end
  122. 1 def getAttackStringWhenCriticalCall(index, diceCount)
  123. 12 hitLocation = getAttackHitLocation(index + 1)
  124. 12 attackValue = (diceCount * 2)
  125. 12 result = hitLocation + ":攻撃値#{attackValue},"
  126. 12 return result
  127. end
  128. 1 def getAttackStringWhenNomal(index, diceCount)
  129. 24 hitLocation = getAttackHitLocation(index + 1)
  130. 24 attackValue = diceCount
  131. 24 result = hitLocation + ":攻撃値#{attackValue},"
  132. 24 return result
  133. end
  134. # 命中部位表
  135. 1 def getAttackHitLocation(num)
  136. table = [
  137. 36 [1, '頭部'],
  138. [2, '右腕'],
  139. [3, '左腕'],
  140. [4, '右脚'],
  141. [5, '左脚'],
  142. [6, '胴体'],
  143. ]
  144. 36 return get_table_by_number(num, table)
  145. end
  146. end
  147. end
  148. end

lib/bcdice/game_system/BattleTech.rb

98.96% lines covered

95.31% branches covered

193 relevant lines. 191 lines covered and 2 lines missed.
64 total branches, 61 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/format'
  3. 1 require 'bcdice/command/parser'
  4. 1 require 'bcdice/dice_table/table'
  5. 1 require 'bcdice/dice_table/range_table'
  6. 1 module BCDice
  7. 1 module GameSystem
  8. 1 class BattleTech < Base
  9. # ゲームシステムの識別子
  10. 1 ID = 'BattleTech'
  11. # ゲームシステム名
  12. 1 NAME = 'バトルテック'
  13. # ゲームシステム名の読みがな
  14. 1 SORT_KEY = 'はとるてつく'
  15. # ダイスボットの使い方
  16. 1 HELP_MESSAGE = <<~MESSAGETEXT
  17. ・判定方法
  18.  (回数)BT(ダメージ)(部位)+(基本値)>=(目標値)
  19.  回数は省略時 1固定。
  20.  部位はC(正面)R(右)、L(左)。省略時はC(正面)固定
  21.  U(上半身)、L(下半身)を組み合わせ CU/RU/LU/CL/RL/LLも指定可能
  22.  例)BT3+2>=4
  23.   正面からダメージ3の攻撃を技能ベース2目標値4で1回判定
  24.  例)2BT3RL+5>=8
  25.   右下半身にダメージ3の攻撃を技能ベース5目標値8で2回判定
  26.  ミサイルによるダメージは BT(ダメージ) の代わりに SRM2/4/6, LRM5/10/15/20 を指定
  27.  例)3SRM6LU+5>=8
  28.   左上半身にSRM6連を技能ベース5目標値8で3回判定
  29. BT(ダメージ) の代わりに PPC を指定するとダメージ10で判定
  30. 例)2PPCR+3>=10
  31.  右側からPPC(ダメージ10)による攻撃を技能ベース3目標値10で2回判定
  32. ・CT:致命的命中表
  33. ・DW:転倒後の向き表
  34. ・CDx:メック戦士意識維持ロール。ダメージ値x(1〜6)で判定 例)CD3
  35. MESSAGETEXT
  36. 1 register_prefix('\d*SRM', '\d*LRM', '\d*BT', '\d*PPC', 'CT', 'DW', 'CD')
  37. # 致命的命中が発生しない上限値
  38. 1 NO_CRITICAL_HIT_LIMIT = 7
  39. # @return [Command::Parser] PPCコマンドの構文解析器
  40. 1 def self.ppc_parser
  41. 32 then: 31 else: 1 return @ppc_parser if defined?(@ppc_parser) && @ppc_parser
  42. 1 @ppc_parser = Command::Parser.new(/PPC(?:[LCR][LU]?)?/, round_type: RoundType::FLOOR)
  43. 1 @ppc_parser.enable_prefix_number
  44. 1 @ppc_parser.restrict_cmp_op_to(:>=)
  45. 1 @ppc_parser
  46. end
  47. # @return [Command::Parser] PPCコマンドの構文解析器
  48. 1 def ppc_parser
  49. 32 self.class.ppc_parser
  50. end
  51. 1 def eval_game_system_specific_command(command)
  52. 37 result = roll_tables(command, TABLES)
  53. 37 then: 5 else: 32 return result if result
  54. 32 then: 5 else: 27 if (ppc_parse_result = ppc_parser.parse(command))
  55. 5 return execute_ppc(ppc_parse_result)
  56. end
  57. 27 count = 1
  58. 27 then: 6 else: 21 if command =~ /^(\d+)(.+)/
  59. 6 count = Regexp.last_match(1).to_i
  60. 6 command = Regexp.last_match(2)
  61. end
  62. 27 debug('executeCommandCatched count', count)
  63. 27 debug('executeCommandCatched command', command)
  64. 27 else: 3 case command
  65. when: 3 when /\ACD([1-6])\z/
  66. 3 damage = Regexp.last_match(1).to_i
  67. 3 return consciousness_roll(damage)
  68. when: 11 when /^((S|L)RM\d+)(.+)/
  69. 11 tail = Regexp.last_match(3)
  70. 11 type = Regexp.last_match(1)
  71. 22 damageFunc = lambda { getXrmDamage(type) }
  72. 11 return getHitResult(count, damageFunc, tail)
  73. when: 10 when /^BT(\d+)(.+)/
  74. 10 debug('BT pattern')
  75. 10 tail = Regexp.last_match(2)
  76. 10 damageValue = Regexp.last_match(1).to_i
  77. 23 damageFunc = lambda { damageValue }
  78. 10 return getHitResult(count, damageFunc, tail)
  79. end
  80. 3 return nil
  81. rescue UnknownXRMError
  82. 1 return nil
  83. end
  84. 1 class UnknownXRMError < StandardError; end
  85. 1 def getXrmDamage(type)
  86. 11 else: 10 then: 1 raise UnknownXRMError, "unknown XRM: #{type}" unless XRM_DAMAGE_TABLES.key?(type)
  87. 10 table = XRM_DAMAGE_TABLES[type]
  88. 10 roll_result = table.roll(@randomizer)
  89. 10 lrm = type.start_with?('L')
  90. 10 damage = roll_result.content
  91. 10 then: 7 else: 3 modified_damage = lrm ? damage : (2 * damage)
  92. 10 return modified_damage, roll_result.sum, lrm
  93. end
  94. 1 LRM_LIMIT = 5
  95. 1 def getHitResult(count, damageFunc, tail)
  96. 26 m = /\A([LCR][LU]?)?(\+\d+)?>=(\d+)/.match(tail)
  97. 26 else: 26 then: 0 return nil unless m
  98. 26 side = m[1] || 'C'
  99. 26 baseString = m[2]
  100. 26 target = m[3].to_i
  101. 26 base = getBaseValue(baseString)
  102. 26 debug("side, base, target", side, base, target)
  103. 26 partTable = HitPart::TABLES[side]
  104. 26 resultLines = []
  105. 26 damages = {}
  106. 26 hitCount = 0
  107. 26 count.times do
  108. 32 isHit, hitResult = getHitText(base, target)
  109. 32 then: 29 else: 3 if isHit
  110. 29 hitCount += 1
  111. 29 damages, damageText = getDamages(damageFunc, partTable, damages)
  112. 28 hitResult += damageText
  113. end
  114. 31 resultLines << hitResult
  115. end
  116. # 命中したか?
  117. 25 hit = hitCount > 0
  118. 25 hitCountText = " > #{hitCount}回命中"
  119. hitDetails =
  120. 25 then: 24 if hit
  121. 24 "#{hitCountText} 命中箇所:#{getTotalDamage(damages)}"
  122. else: 1 else
  123. 1 hitCountText
  124. end
  125. 25 resultLines.push(hitDetails)
  126. 25 resultText = resultLines.join("\n")
  127. 25 then: 24 else: 1 return hit ? Result.success(resultText) : Result.failure(resultText)
  128. end
  129. 1 def getBaseValue(baseString)
  130. 26 base = 0
  131. 26 then: 22 else: 4 return base if baseString.nil?
  132. 4 base = ArithmeticEvaluator.eval(baseString)
  133. 4 return base
  134. end
  135. 1 def getHitText(base, target)
  136. 32 dice1 = @randomizer.roll_once(6)
  137. 32 dice2 = @randomizer.roll_once(6)
  138. 32 total = dice1 + dice2 + base
  139. 32 isHit = (total >= target)
  140. 32 then: 7 else: 25 baseString = (base > 0 ? "+#{base}" : "")
  141. 32 result = "#{total}[#{dice1},#{dice2}#{baseString}]>=#{target} > "
  142. 32 then: 29 if isHit
  143. 29 result += "命中 > "
  144. else: 3 else
  145. 3 result += "外れ"
  146. end
  147. 32 return isHit, result
  148. end
  149. # @param [Proc] damageFunc ダメージを返す手続き
  150. # @param [RangeTable] partTable 命中部位表
  151. # @param [Hash] damages 蓄積したダメージの情報
  152. 1 def getDamages(damageFunc, partTable, damages)
  153. 29 resultText = ''
  154. 29 damage, dice, isLrm = damageFunc.call()
  155. 28 damagePartCount = 1
  156. 28 then: 7 else: 21 if isLrm
  157. 7 damagePartCount = (1.0 * damage / LRM_LIMIT).ceil
  158. 7 resultText += "[#{dice}] #{damage}点"
  159. end
  160. 28 damagePartCount.times do |damageIndex|
  161. 32 currentDamage, damageText = getDamageInfo(dice, damage, isLrm, damageIndex)
  162. 32 text, part, criticalText = getHitResultOne(damageText, partTable)
  163. 32 then: 11 else: 21 resultText += " " if isLrm
  164. 32 resultText += text
  165. 32 then: 27 else: 5 if damages[part].nil?
  166. 27 damages[part] = {
  167. partDamages: [],
  168. criticals: [],
  169. }
  170. end
  171. 32 damages[part][:partDamages] << currentDamage
  172. 32 else: 26 then: 6 damages[part][:criticals] << criticalText unless criticalText.empty?
  173. end
  174. 28 return damages, resultText
  175. end
  176. 1 def getDamageInfo(dice, damage, isLrm, index)
  177. 32 then: 18 else: 14 return damage, damage.to_s if dice.nil?
  178. 14 else: 11 then: 3 return damage, "[#{dice}] #{damage}" unless isLrm
  179. 11 currentDamage = damage - (LRM_LIMIT * index)
  180. 11 then: 4 else: 7 if currentDamage > LRM_LIMIT
  181. 4 currentDamage = LRM_LIMIT
  182. end
  183. 11 return currentDamage, currentDamage.to_s
  184. end
  185. 1 def getTotalDamage(damages)
  186. 24 parts = ['頭',
  187. '胴中央',
  188. '右胴',
  189. '左胴',
  190. '右脚',
  191. '左脚',
  192. '右腕',
  193. '左腕',]
  194. 24 allDamage = 0
  195. 24 damageTexts = []
  196. 24 parts.each do |part|
  197. 192 damageInfo = damages.delete(part)
  198. 192 then: 165 else: 27 next if damageInfo.nil?
  199. 59 damage = damageInfo[:partDamages].inject(0) { |sum, i| sum + i }
  200. 27 allDamage += damage
  201. 27 damageCount = damageInfo[:partDamages].size
  202. 27 criticals = damageInfo[:criticals]
  203. 27 text = ""
  204. 27 text += "#{part}(#{damageCount}回) #{damage}点"
  205. 27 else: 24 then: 3 text += " #{criticals.join(' ')}" unless criticals.empty?
  206. 27 damageTexts << text
  207. end
  208. 24 else: 24 then: 0 unless damages.empty?
  209. raise "damages rest!! #{damages.inspect()}"
  210. end
  211. 24 result = damageTexts.join(" / ")
  212. 24 result += " > 合計ダメージ #{allDamage}点"
  213. 24 return result
  214. end
  215. # 攻撃を1回行い、その結果を返す
  216. # @param [String] damage_text ダメージを表す文字列
  217. # @param [RangeTable] hit_part_table 命中部位表
  218. 1 def getHitResultOne(damage_text, hit_part_table)
  219. 32 hit_part_roll_result = hit_part_table.roll(@randomizer)
  220. 32 hit_part = hit_part_roll_result.content
  221. critical_hit_may_occur_str =
  222. 32 then: 7 else: 25 hit_part.critical_hit_may_occur ? '(致命的命中)' : ''
  223. result_parts = [
  224. [
  225. 32 "[#{hit_part_roll_result.sum}]",
  226. "#{hit_part.name}#{critical_hit_may_occur_str}",
  227. "#{damage_text}点",
  228. ].join(' ')
  229. ]
  230. 32 criticalText = ''
  231. 32 then: 7 else: 25 if hit_part.critical_hit_may_occur
  232. 7 ct_roll_result = TABLES['CT'].roll(@randomizer)
  233. # 致命的命中が発生したか
  234. 7 then: 6 else: 1 if ct_roll_result.sum > NO_CRITICAL_HIT_LIMIT
  235. 6 criticalText = ct_roll_result.content
  236. end
  237. 7 result_parts.push("[#{ct_roll_result.sum}] #{ct_roll_result.content}")
  238. end
  239. # TODO: 構造体で表現する
  240. 32 return result_parts.join(' > '), hit_part.name, criticalText
  241. end
  242. # メック戦士意識維持ロールを行う
  243. #
  244. # damageが6の場合は死亡。
  245. # damageが5以下の場合は、2d6の結果が意識維持表の値以上かの成功判定。
  246. #
  247. # @param damage [Integer] メック戦士へのダメージ(1〜6)
  248. # @return [Result]
  249. # @see 「BattleTech: A Game of Armored Combat」ルールブックp. 44
  250. 1 def consciousness_roll(damage)
  251. 3 else: 3 then: 0 unless (1..6).include?(damage)
  252. return nil
  253. end
  254. 3 command = "CD#{damage}"
  255. 3 then: 1 else: 2 if damage == 6
  256. 1 return Result.fumble("#{command} > 死亡")
  257. end
  258. 2 consciousness_table = {
  259. 1 => 3,
  260. 2 => 5,
  261. 3 => 7,
  262. 4 => 10,
  263. 5 => 11,
  264. }
  265. 2 target = consciousness_table[damage]
  266. 2 expr = "(2D6>=#{target})"
  267. 2 values = @randomizer.roll_barabara(2, 6)
  268. 2 sum = values.sum
  269. 2 values_str = values.join(",")
  270. 2 sum_and_values = "#{sum}[#{values_str}]"
  271. 2 success = sum >= target
  272. 2 then: 1 else: 1 result = success ? "成功" : "失敗"
  273. parts = [
  274. 2 command,
  275. expr,
  276. sum_and_values,
  277. sum,
  278. result,
  279. ]
  280. 2 text = parts.join(" > ")
  281. 2 then: 1 else: 1 return success ? Result.success(text) : Result.failure(text)
  282. end
  283. # PPCコマンドを実行する
  284. # @param parse_result [Command::Parsed] PPCコマンドの構文解析結果
  285. # @return [Result, nil]
  286. 1 def execute_ppc(parse_result)
  287. 5 count = parse_result.prefix_number || 1
  288. # getHitResult() の引数tailの形に合わせる
  289. # TODO: 攻撃を表すクラスに変える
  290. # "PPC" 以降の部位指定
  291. 5 side = parse_result.command[3..-1]
  292. 5 modifier = Format.modifier(parse_result.modify_number)
  293. 5 target = parse_result.target_number
  294. 5 tail = "#{side}#{modifier}>=#{target}"
  295. # ダメージ10固定で命中判定を行う
  296. 10 return getHitResult(count, lambda { 10 }, tail)
  297. end
  298. # 表の集合
  299. TABLES = {
  300. 1 'CT' => DiceTable::RangeTable.new(
  301. '致命的命中表',
  302. '2D6',
  303. [
  304. [2..NO_CRITICAL_HIT_LIMIT, '致命的命中はなかった'],
  305. [8..9, '1箇所の致命的命中'],
  306. [10..11, '2箇所の致命的命中'],
  307. [12, 'その部位が吹き飛ぶ(腕、脚、頭)または3箇所の致命的命中(胴)'],
  308. ]
  309. ),
  310. 'DW' => DiceTable::Table.new(
  311. '転倒後の向き表',
  312. '1D6',
  313. [
  314. '同じ(前面から転倒) 正面/背面',
  315. '1ヘクスサイド右(側面から転倒) 右側面',
  316. '2ヘクスサイド右(側面から転倒) 右側面',
  317. '180度逆(背面から転倒) 正面/背面',
  318. '2ヘクスサイド左(側面から転倒) 左側面',
  319. '1ヘクスサイド左(側面から転倒) 左側面',
  320. ]
  321. )
  322. }.freeze
  323. # 命中部位を表す構造体
  324. # @!attribute [rw] name
  325. # @return [String] 部位名
  326. # @!attribute [rw] critical_hit_may_occur
  327. # @return [Boolean] 致命的命中が発生し得るか
  328. 1 HitPart = Struct.new(:name, :critical_hit_may_occur)
  329. 1 class HitPart
  330. 1 LEFT_TORSO = '左胴'
  331. 1 CENTER_TORSO = '胴中央'
  332. 1 RIGHT_TORSO = '右胴'
  333. 1 LEFT_ARM = '左腕'
  334. 1 RIGHT_ARM = '右腕'
  335. 1 LEFT_LEG = '左脚'
  336. 1 RIGHT_LEG = '右脚'
  337. 1 HEAD = '頭'
  338. # 命中部位表
  339. TABLES = {
  340. 1 'L' => DiceTable::RangeTable.new(
  341. '命中部位表(左)',
  342. '2D6',
  343. [
  344. [2, new(LEFT_TORSO, true)],
  345. [3, new(LEFT_LEG, false)],
  346. [4..5, new(LEFT_ARM, false)],
  347. [6, new(LEFT_LEG, false)],
  348. [7, new(LEFT_TORSO, false)],
  349. [8, new(CENTER_TORSO, false)],
  350. [9, new(RIGHT_TORSO, false)],
  351. [10, new(RIGHT_ARM, false)],
  352. [11, new(RIGHT_LEG, false)],
  353. [12, new(HEAD, false)],
  354. ]
  355. ),
  356. 'C' => DiceTable::RangeTable.new(
  357. '命中部位表(正面)',
  358. '2D6',
  359. [
  360. [2, new(CENTER_TORSO, true)],
  361. [3..4, new(RIGHT_ARM, false)],
  362. [5, new(RIGHT_LEG, false)],
  363. [6, new(RIGHT_TORSO, false)],
  364. [7, new(CENTER_TORSO, false)],
  365. [8, new(LEFT_TORSO, false)],
  366. [9, new(LEFT_LEG, false)],
  367. [10..11, new(LEFT_ARM, false)],
  368. [12, new(HEAD, false)],
  369. ]
  370. ),
  371. 'R' => DiceTable::RangeTable.new(
  372. '命中部位表(右)',
  373. '2D6',
  374. [
  375. [2, new(RIGHT_TORSO, true)],
  376. [3, new(RIGHT_LEG, false)],
  377. [4..5, new(RIGHT_ARM, false)],
  378. [6, new(RIGHT_LEG, false)],
  379. [7, new(RIGHT_TORSO, false)],
  380. [8, new(CENTER_TORSO, false)],
  381. [9, new(LEFT_TORSO, false)],
  382. [10, new(LEFT_ARM, false)],
  383. [11, new(LEFT_LEG, false)],
  384. [12, new(HEAD, false)],
  385. ]
  386. ),
  387. 'LU' => DiceTable::RangeTable.new(
  388. '命中部位表(左上半身)',
  389. '1D6',
  390. [
  391. [1..2, new(LEFT_TORSO, false)],
  392. [3, new(CENTER_TORSO, false)],
  393. [4..5, new(LEFT_ARM, false)],
  394. [6, new(HEAD, false)],
  395. ]
  396. ),
  397. # TODO: 普通のTableで書く
  398. 'CU' => DiceTable::RangeTable.new(
  399. '命中部位表(正面上半身)',
  400. '1D6',
  401. [
  402. [1, new(LEFT_ARM, false)],
  403. [2, new(LEFT_TORSO, false)],
  404. [3, new(CENTER_TORSO, false)],
  405. [4, new(RIGHT_TORSO, false)],
  406. [5, new(RIGHT_ARM, false)],
  407. [6, new(HEAD, false)],
  408. ]
  409. ),
  410. 'RU' => DiceTable::RangeTable.new(
  411. '命中部位表(右上半身)',
  412. '1D6',
  413. [
  414. [1..2, new(RIGHT_TORSO, false)],
  415. [3, new(CENTER_TORSO, false)],
  416. [4..5, new(RIGHT_ARM, false)],
  417. [6, new(HEAD, false)],
  418. ]
  419. ),
  420. 'LL' => DiceTable::RangeTable.new(
  421. '命中部位表(左下半身)',
  422. '1D6',
  423. [
  424. [1..6, new(LEFT_LEG, false)],
  425. ]
  426. ),
  427. 'CL' => DiceTable::RangeTable.new(
  428. '命中部位表(右下半身)',
  429. '1D6',
  430. [
  431. [1..3, new(RIGHT_LEG, false)],
  432. [4..6, new(LEFT_LEG, false)],
  433. ]
  434. ),
  435. 'RL' => DiceTable::RangeTable.new(
  436. '命中部位表(右下半身)',
  437. '1D6',
  438. [
  439. [1..6, new(RIGHT_LEG, false)],
  440. ]
  441. ),
  442. }.freeze
  443. end
  444. # ミサイルダメージ表
  445. XRM_DAMAGE_TABLES = {
  446. 1 'SRM2' => DiceTable::RangeTable.new(
  447. 'SRM2ダメージ表',
  448. '2D6',
  449. [
  450. [2..7, 1],
  451. [8..12, 2],
  452. ]
  453. ),
  454. 'SRM4' => DiceTable::RangeTable.new(
  455. 'SRM4ダメージ表',
  456. '2D6',
  457. [
  458. [2, 1],
  459. [3..6, 2],
  460. [7..10, 3],
  461. [11..12, 4],
  462. ]
  463. ),
  464. 'SRM6' => DiceTable::RangeTable.new(
  465. 'SRM6ダメージ表',
  466. '2D6',
  467. [
  468. [2..3, 2],
  469. [4..5, 3],
  470. [6..8, 4],
  471. [9..10, 5],
  472. [11..12, 6],
  473. ]
  474. ),
  475. 'LRM5' => DiceTable::RangeTable.new(
  476. 'LRM5ダメージ表',
  477. '2D6',
  478. [
  479. [2, 1],
  480. [3..4, 2],
  481. [5..8, 3],
  482. [9..10, 4],
  483. [11..12, 5],
  484. ]
  485. ),
  486. 'LRM10' => DiceTable::RangeTable.new(
  487. 'LRM10ダメージ表',
  488. '2D6',
  489. [
  490. [2..3, 3],
  491. [4, 4],
  492. [5..8, 6],
  493. [9..10, 8],
  494. [11..12, 10],
  495. ]
  496. ),
  497. 'LRM15' => DiceTable::RangeTable.new(
  498. 'LRM15ダメージ表',
  499. '2D6',
  500. [
  501. [2..3, 5],
  502. [4, 6],
  503. [5..8, 9],
  504. [9..10, 12],
  505. [11..12, 15],
  506. ]
  507. ),
  508. 'LRM20' => DiceTable::RangeTable.new(
  509. 'LRM20ダメージ表',
  510. '2D6',
  511. [
  512. [2..3, 6],
  513. [4, 9],
  514. [5..8, 12],
  515. [9..10, 16],
  516. [11..12, 20],
  517. ]
  518. )
  519. }.freeze
  520. end
  521. end
  522. end

lib/bcdice/game_system/BeastBindTrinity.rb

95.9% lines covered

91.67% branches covered

122 relevant lines. 117 lines covered and 5 lines missed.
60 total branches, 55 branches covered and 5 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/arithmetic_evaluator'
  3. 1 require 'bcdice/format'
  4. 1 require 'bcdice/normalize'
  5. 1 require 'bcdice/dice_table/table'
  6. 1 require 'bcdice/dice_table/d66_grid_table'
  7. 1 module BCDice
  8. 1 module GameSystem
  9. 1 class BeastBindTrinity < Base
  10. # ゲームシステムの識別子
  11. 1 ID = 'BeastBindTrinity'
  12. # ゲームシステム名
  13. 1 NAME = 'ビーストバインド トリニティ'
  14. # ゲームシステム名の読みがな
  15. 1 SORT_KEY = 'ひいすとはいんととりにてい'
  16. # ダイスボットの使い方
  17. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  18. ・判定 (nBB+m%w@x#y$z&v)
  19.  n個のD6を振り、出目の大きい2個から達成値を算出。修正mも可能。
  20.  %w、@x、#y、$z、&vはすべて省略可能。
  21. >%w:現在の人間性が w であるとして、クリティカル値(C値)を計算。
  22. ・省略した場合、C値=12として達成値を算出する。
  23. >@x:クリティカル値修正。(加減式でも入力可能)
  24. ・xに直接数字を書くと、C値をその数字に上書きする。
  25.  「絶対にクリティカルしない」状態は、@13など xを13以上に指定すること。
  26. ・xの先頭が「+」か「-」なら、計算したC値にその値を加算。例)@-1、@+2
  27.  この方法でC値をプラスする場合、上限は12となる。
  28. >#y、#Ay:ファンブル値修正。(加減式でも入力可能)
  29. ・yに直接数字を書くと、ファンブル値をその数字に設定。
  30. ・yの数字の先頭が「+」か「-」なら、ファンブル値=2にその数字を加算。例)#+2
  31. ・※#Ayとすると、ファンブルしても達成値を通常通り算出。 例)#A+1
  32. >$z:ダイスの出目をzに固定して判定する。複数指定可。
  33.    《運命歪曲》など「ダイスの1個を振り直す」効果等に使用する。
  34.  例)2BB$1 →ダイスを2個振る判定で、ダイス1個の出目を1で固定
  35.  例)2BB$16→ダイスを2個振る判定で、ダイスの出目を1と6で固定
  36. >&v:出目がv未満のダイスがあれば、出目がvだったものとして達成値を計算する。
  37.  例)2BB&3 →出目3未満(→出目1、2)を出目3だったものとして計算。
  38. ・D66ダイスあり
  39. ・邂逅表:EMO
  40. ・暴露表:EXPO_A
  41. ・魔獣化暴露表:EXPO_B
  42. ・アイドル専用暴露表:EXPO_I
  43. ・アイドル専用魔獣化暴露表:EXPO_J
  44. ・正体判明チャートA~C:FACE_A, FACE_B, FACE_C
  45. INFO_MESSAGE_TEXT
  46. 1 def initialize(command)
  47. 46 super(command)
  48. 46 @d66_sort_type = D66SortType::ASC
  49. end
  50. 1 class BBCommand
  51. 1 def initialize(command)
  52. 38 @command = command
  53. 38 parse()
  54. end
  55. 1 def roll(randomizer)
  56. 38 then: 0 else: 38 if @parse_error
  57. return nil
  58. end
  59. 38 @randomizer = randomizer
  60. 38 dice_list_org = roll_with_dice_pool()
  61. 38 then: 0 else: 38 if dice_list_org.empty?
  62. return "ERROR:振るダイスの数が0個です"
  63. end
  64. 112 dice_list_filtered = dice_list_org.map { |dice| [dice, @dice_value_lower_limit].max }.sort
  65. 38 @dice_total = dice_list_filtered.last(2).inject(0, :+)
  66. 38 total = calc_total()
  67. 38 then: 2 else: 36 dice_list_org_str = "[#{dice_list_org.join(',')}]" if dice_list_filtered != dice_list_org
  68. 38 result = result_compare(total)
  69. 38 result.critical = critical?
  70. 38 result.fumble = fumble?
  71. dice_status =
  72. 38 then: 4 if result.fumble?
  73. 4 else: 34 "ファンブル"
  74. 34 then: 17 else: 17 elsif result.critical?
  75. 17 "クリティカル"
  76. end
  77. result_str =
  78. 38 then: 11 if result.success?
  79. 11 else: 27 "成功"
  80. 27 then: 7 else: 20 elsif result.failure?
  81. 7 "失敗"
  82. end
  83. sequence = [
  84. 38 command_expr(),
  85. dice_list_org_str,
  86. interim_expr(dice_list_filtered),
  87. dice_status,
  88. total.to_s,
  89. result_str
  90. ].compact
  91. 38 result.text = sequence.join(" > ")
  92. 38 return result
  93. end
  94. 1 private
  95. 1 def parse()
  96. 38 m = /^(\d+)(?:R6|BB6?)((?:[+-]\d+)+)?(?:%(-?\d+))?(?:@([+\-\d]+))?(?:#(A)?([+\-\d]+))?(?:\$([1-6]+))?(?:&([1-6]))?(?:([>=]+)(\d+))?$/.match(@command)
  97. 38 else: 38 then: 0 unless m
  98. @parse_error = true
  99. return
  100. end
  101. 38 @dice_num = m[1].to_i
  102. 38 then: 36 else: 2 @modify_number = m[2] ? ArithmeticEvaluator.eval(m[2]) : 0
  103. 38 @critical = parse_critical(m[3], m[4])
  104. 38 @keep_value_on_fumble = !m[5].nil?
  105. 38 @fumble = parse_fumble(m[6])
  106. 38 then: 2 else: 36 @dice_pool = m[7] ? m[7].split("").map(&:to_i) : []
  107. 38 then: 0 else: 38 @dice_pool.pop(@dice_pool.size - @dice_num) if @dice_pool.size > @dice_num
  108. 38 @dice_value_lower_limit = m[8].to_i
  109. 38 @cmp_op = Normalize.comparison_operator(m[9])
  110. 38 then: 18 else: 20 @target_number = m[10]&.to_i
  111. 38 @parse_error = false
  112. end
  113. # @param humanity [String, nil]
  114. # @param atmark [String, nil]
  115. # @return [Integer]
  116. 1 def parse_critical(humanity, atmark)
  117. 38 then: 18 else: 20 humanity = humanity ? humanity.to_i : 99
  118. 38 then: 15 else: 23 atmark_value = atmark ? ArithmeticEvaluator.eval(atmark) : 0
  119. critical =
  120. 38 then: 6 if /^[+-]/.match(atmark)
  121. 6 else: 32 [critical_from_humanity(humanity) + atmark_value, 12].min
  122. 32 then: 9 elsif atmark
  123. 9 atmark_value
  124. else: 23 else
  125. 23 critical_from_humanity(humanity)
  126. end
  127. 38 return critical
  128. end
  129. 1 def critical_from_humanity(humanity)
  130. 29 then: 3 if humanity <= 0
  131. 3 else: 26 9
  132. 26 then: 7 elsif humanity <= 20
  133. 7 else: 19 10
  134. 19 then: 3 elsif humanity <= 40
  135. 3 11
  136. else: 16 else
  137. 16 12
  138. end
  139. end
  140. # @param sharp [String, nil]
  141. # @return [Integer]
  142. 1 def parse_fumble(sharp)
  143. 38 then: 10 else: 28 sharp_value = sharp ? ArithmeticEvaluator.eval(sharp) : 0
  144. 38 then: 2 if /^[+-]/.match(sharp)
  145. 2 else: 36 2 + sharp_value
  146. 36 then: 8 elsif sharp
  147. 8 sharp_value
  148. else: 28 else
  149. 28 2
  150. end
  151. end
  152. 1 def roll_with_dice_pool
  153. 38 dice_times = @dice_num - @dice_pool.size
  154. 38 dice_list = @randomizer.roll_barabara(dice_times, 6) + @dice_pool
  155. 38 return dice_list.sort
  156. end
  157. 1 def command_expr
  158. 38 modifier = Format.modifier(@modify_number)
  159. 38 "(#{@dice_num}BB#{modifier}@#{@critical}\##{@fumble}#{@cmp_op}#{@target_number})"
  160. end
  161. 1 def interim_expr(dice_list)
  162. 38 expr = "#{@dice_total}[#{dice_list.join(',')}]#{Format.modifier(@modify_number)}"
  163. 38 then: 17 else: 21 expr += "+20" if critical?
  164. 38 return expr
  165. end
  166. 1 def fumble?
  167. 76 @dice_total <= @fumble
  168. end
  169. 1 def critical?
  170. 110 @dice_total >= @critical
  171. end
  172. 1 def calc_total
  173. 38 total = @dice_total + @modify_number
  174. 38 then: 4 if fumble?
  175. 4 else: 34 else: 2 then: 2 total = 0 unless @keep_value_on_fumble
  176. 34 then: 17 else: 17 elsif critical?
  177. 17 total += 20
  178. end
  179. 38 then: 0 else: 38 if total < 0
  180. total = 0
  181. end
  182. 38 return total
  183. end
  184. 1 def result_compare(total)
  185. 38 then: 18 if @cmp_op
  186. 18 then: 11 if total.send(@cmp_op, @target_number)
  187. 11 Result.success(nil)
  188. else: 7 else
  189. 7 Result.failure(nil)
  190. end
  191. else: 20 else
  192. 20 Result.new
  193. end
  194. end
  195. end
  196. 1 def eval_game_system_specific_command(command)
  197. 46 then: 8 else: 38 if (ret = roll_tables(command, TABLES))
  198. 8 return ret
  199. end
  200. 38 bb = BBCommand.new(command)
  201. 38 return bb.roll(@randomizer)
  202. end
  203. TABLES = {
  204. 1 'EMO' => DiceTable::D66GridTable.new(
  205. '邂逅表',
  206. [
  207. ['家族', '家族', '信頼', '信頼', '忘却', '忘却'],
  208. ['慈愛', '慈愛', '憧憬', '憧憬', '感銘', '感銘'],
  209. ['同志', '同志', '幼子', '幼子', '興味', '興味'],
  210. ['ビジネス', 'ビジネス', '師事', '師事', '好敵手', '好敵手'],
  211. ['友情', '友情', '忠誠', '忠誠', '恐怖', '恐怖'],
  212. ['執着', '執着', '軽蔑', '軽蔑', '憎悪', '憎悪'],
  213. ]
  214. ),
  215. 'EXPO_A' => DiceTable::Table.new(
  216. '暴露表',
  217. '1D6',
  218. [
  219. '噂になるがすぐ忘れられる',
  220. '都市伝説として処理される',
  221. 'ワイドショーをにぎわす',
  222. 'シナリオ中[迫害状態]になる',
  223. '絆の対象ひとりに正体が知られる',
  224. '魔獣化暴露表へ'
  225. ]
  226. ),
  227. 'EXPO_B' => DiceTable::Table.new(
  228. '魔獣化暴露表',
  229. '1D6',
  230. [
  231. 'トンデモ業界の伝説になる',
  232. 'シナリオ中[迫害状態]になる',
  233. 'シナリオ中[迫害状態]になる',
  234. '絆の対象ひとりに正体が知られる',
  235. '絆の対象ひとりに正体が知られる',
  236. '自衛隊退魔部隊×2D6体の襲撃'
  237. ]
  238. ),
  239. 'EXPO_I' => DiceTable::Table.new(
  240. 'アイドル専用暴露表',
  241. '1D6',
  242. [
  243. '愉快な伝説として人気になる',
  244. 'ワイドショーをにぎわす',
  245. '炎上。シナリオ中[迫害状態]',
  246. '所属事務所に2D6時間説教される',
  247. '絆の対象ひとりに正体が知られる',
  248. 'アイドル専用魔獣化暴露表へ'
  249. ]
  250. ),
  251. 'EXPO_J' => DiceTable::Table.new(
  252. 'アイドル専用魔獣化暴露表',
  253. '1D6',
  254. [
  255. 'シナリオ中[迫害状態]になる',
  256. 'シナリオ中[迫害状態]になる',
  257. '絆の対象ひとりに正体が知られる',
  258. '事務所から契約を解除される',
  259. '絆の対象ひとりに正体が知られる',
  260. '1D6本のレギュラー番組を失う'
  261. ]
  262. ),
  263. 'FACE_A' => DiceTable::Table.new(
  264. '正体判明チャートA',
  265. '1D6',
  266. [
  267. 'あなたを受け入れてくれる',
  268. 'あなたを受け入れてくれる',
  269. '絆が(拒絶)に書き換わる',
  270. '絆がエゴに書き換わる',
  271. '気絶しその事実を忘れる',
  272. '精神崩壊する'
  273. ]
  274. ),
  275. 'FACE_B' => DiceTable::Table.new(
  276. '正体判明チャートB',
  277. '1D6',
  278. [
  279. 'あなたを受け入れてくれる',
  280. '狂乱し攻撃してくる',
  281. '退場。その場から逃亡。暴露表へ',
  282. '絆がエゴに書き換わる',
  283. '精神崩壊する',
  284. '精神崩壊する'
  285. ]
  286. ),
  287. 'FACE_C' => DiceTable::Table.new(
  288. '正体判明チャートC',
  289. '1D6',
  290. [
  291. 'あなたを受け入れてくれる',
  292. '退場。その場から逃亡。暴露表へ',
  293. '退場。その場から逃亡。暴露表へ',
  294. '絆がエゴに書き換わる',
  295. '精神崩壊する',
  296. '精神崩壊する'
  297. ]
  298. ),
  299. }.freeze
  300. 1 register_prefix('\d+BB', '\d+R6', TABLES.keys)
  301. end
  302. end
  303. end

lib/bcdice/game_system/BeginningIdol.rb

100.0% lines covered

96.3% branches covered

113 relevant lines. 113 lines covered and 0 lines missed.
54 total branches, 52 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/beginning_idol/table'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class BeginningIdol < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'BeginningIdol'
  8. # ゲームシステム名
  9. 1 NAME = 'ビギニングアイドル'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'ひきにんくあいとる'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. これは、2015年に新書サイズで発売された『駆け出しアイドルRPG ビギニングアイドル チャレンジガールズ』およびそのサプリメントに対応したコマンドです。
  15. ・パフォーマンス [r]PDn[+m/-m](r:場に残った出目 n:振る数 m:修正値)
  16. ・ワールドセッティング仕事表 BWT:大手芸能プロ LWT:弱小芸能プロ
  17.  TWT:ライブシアター CWT:アイドル部 LO[n]:地方アイドル(n:チャンス)
  18.  SU:情熱の夏 WI:ぬくもりの冬 NA:大自然 GA:女学園 BA:アカデミー
  19. ・仕事表 WT VA:バラエティ MU:音楽関係 DR:ドラマ関係
  20.  VI:ビジュアル関係 SP:スポーツ CHR:クリスマス PAR:パートナー関係
  21.  SW:お菓子 AN:動物 MOV:映画 FA:ファンタジー
  22. ・ランダムイベント RE
  23. ・ハプニング表 HA
  24. ・特技リスト AT[n](n:分野No.)
  25. ・アイドルスキル修得表 SGT:チャレンジガールズ RS:ロードトゥプリンス
  26. ・変調 BT[n](n:発生数)
  27. ・アイテム IT[n](n:獲得数)
  28. ・アクセサリー ACT:種別決定 ACB:ブランド決定 ACE:効果表
  29. ・衣装 DT:チャレンジガールズ RC:ロードトゥプリンス FC:フォーチュンスターズ
  30. ・無茶ぶり表 LUR:地方アイドル SUR:情熱の夏 WUR:ぬくもりの冬
  31.  NUR:大自然 GUR:女学園 BUR:アカデミー
  32. ・センタールール HW:向かい風シーン表 FL:駆け出しシーン表 LN:孤独表
  33.  マイスキル【MS:名前決定 MSE:効果表】 演出表【ST FST:ファンタジー】
  34. ・合宿ルール 散策表【SH:ショッピングモール MO:山 SEA:海 SPA:温泉街】
  35.  TN:夜語りシチュエーション表 成長表【CG:コモン GG:ゴールド】
  36. ・サビ表 CHO SCH:情熱の夏 WCH:ぬくもりの冬 NCH:大自然
  37.  GCH:女性向け PCH:力強い
  38. ・キャラ空白表 CBT:チャレンジガールズ RCB:ロードトゥプリンス
  39. ・趣味空白表 HBT:チャレンジガールズ RHB:ロードトゥプリンス
  40. ・マスコット暴走表 RU
  41. ・アイドル熱湯風呂 nC:バーストタイム(n:温度) BU:バースト表
  42. ・攻撃 n[S]A[r][+m/-m](n:振る数 S:失敗しない r:取り除く出目 m:修正値)
  43. ・かんたんパーソン表 SIP
  44. ・会場表
  45.  BVT:大手芸能プロ LVT:弱小芸能プロ TVT:ライブシアター CVT:アイドル部
  46. ・場所表
  47.  BST:大手芸能プロ LST:弱小芸能プロ TST:ライブシアター CST:アイドル部
  48. ・プレッシャー種別決定表
  49.  BPT:大手芸能プロ LPT:弱小芸能プロ TPT:ライブシアター CPT:アイドル部
  50. ・道具表
  51.  BIT:大手芸能プロ LIT:弱小芸能プロ TIT:ライブシアター CIT:アイドル部
  52. []内は省略可 D66入れ替えあり
  53. INFO_MESSAGE_TEXT
  54. 1 register_prefix(
  55. SKILL_TABLE.prefixes,
  56. 'IT',
  57. 'BT',
  58. '\d{2}C',
  59. '\d+S?A',
  60. '[1-7]*PD'
  61. )
  62. 1 def initialize(command)
  63. 397 super(command)
  64. 397 @sort_add_dice = true
  65. 397 @d66_sort_type = D66SortType::ASC
  66. end
  67. 1 def result_nd6(total, dice_total, _value_list, cmp_op, target)
  68. 18 then: 2 else: 16 return nil if target == '?'
  69. 16 else: 16 then: 0 return nil unless cmp_op == :>=
  70. 16 then: 2 if dice_total <= 2
  71. 2 else: 14 Result.fumble(translate("BeginningIdol.fumble"))
  72. 14 then: 6 elsif dice_total >= 12
  73. 6 else: 8 Result.critical(translate("BeginningIdol.special"))
  74. 8 then: 4 elsif total >= target
  75. 4 Result.success(translate("success"))
  76. else: 4 else
  77. 4 Result.failure(translate("failure"))
  78. end
  79. end
  80. 1 alias check_2D6 check_nD6
  81. 1 def eval_game_system_specific_command(command)
  82. 369 roll_attack(command) ||
  83. roll_burst(command) ||
  84. roll_performance(command) ||
  85. self.class::SKILL_TABLE.roll_command(@randomizer, command) ||
  86. self.class::ITEM_TABLE.roll_command(@randomizer, command) ||
  87. self.class::BAD_STATUS_TABLE.roll_command(@randomizer, command) ||
  88. self.class::LOCAL_WORK_TABLE.roll_command(@randomizer, command) ||
  89. roll_tables(command, self.class::TABLES)
  90. end
  91. 1 private
  92. 1 def roll_burst(command)
  93. 353 m = /^(\d{2})C$/.match(command)
  94. 353 else: 12 then: 341 unless m
  95. 341 return nil
  96. end
  97. 12 degrees = m[1].to_i
  98. 12 then: 4 else: 8 if (degrees < 45) || (degrees > 55)
  99. 4 return nil
  100. end
  101. counts =
  102. 8 then: 2 if degrees <= 49
  103. 2 else: 6 3
  104. 6 then: 2 elsif degrees <= 52
  105. 2 else: 4 4
  106. 4 then: 2 elsif degrees <= 54
  107. 2 5
  108. else: 2 else
  109. 2 6
  110. end
  111. 8 dice_list = @randomizer.roll_barabara(counts, 6).sort
  112. 8 total = dice_list.sum() + degrees
  113. result =
  114. 8 then: 2 if total >= 80
  115. 2 else: 6 translate("BeginningIdol.burst.burst")
  116. 6 then: 2 elsif total >= 75
  117. 2 else: 4 translate("BeginningIdol.burst.critical_success")
  118. 4 then: 2 elsif total >= 65
  119. 2 translate("BeginningIdol.burst.success")
  120. else: 2 else
  121. 2 translate("failure")
  122. end
  123. 8 name = translate("BeginningIdol.burst.name")
  124. 8 return "#{name} > #{degrees}+[#{dice_list.join(',')}] > #{total} > #{result}"
  125. end
  126. 1 def roll_attack(command)
  127. 369 m = /^(\d+)(S?)A([1-6]*)([+-]\d+)?$/.match(command)
  128. 369 else: 16 then: 353 unless m
  129. 353 return nil
  130. end
  131. 16 counts = m[1].to_i
  132. 16 then: 0 else: 16 return nil if counts <= 0
  133. 16 sure = !m[2].empty?
  134. 16 remove = m[3].each_char.map(&:to_i)
  135. 16 adjust = m[4].to_i
  136. 16 adjust_str = Format.modifier(adjust)
  137. 16 dice = @randomizer.roll_barabara(counts, 6).sort
  138. 16 dice_str = dice.join(",")
  139. 16 dice -= remove
  140. 16 text = "#{translate('BeginningIdol.attack.name')} > [#{dice_str}]#{adjust_str} > "
  141. 16 else: 12 then: 4 unless (dice.count == counts) || dice.empty?
  142. 4 text += "[#{dice.join(',')}]#{adjust_str} > "
  143. end
  144. 16 then: 12 if sure || (dice.count == dice.uniq.count)
  145. 12 total = [dice.sum() + adjust.to_i, 0].max
  146. 12 text += format(translate('BeginningIdol.attack.damage'), total: total)
  147. else: 4 else
  148. 4 text += translate('failure')
  149. end
  150. 16 return text
  151. end
  152. 1 def roll_performance(command)
  153. 345 m = /^([1-7]*)PD(\d+)([+-]\d+)?$/.match(command)
  154. 345 else: 38 then: 307 unless m
  155. 307 return nil
  156. end
  157. 38 counts = m[2].to_i
  158. 38 then: 2 else: 36 return nil if counts <= 0
  159. 36 carry = m[1].chars.map(&:to_i).sort
  160. 36 modifier = m[3].to_i
  161. 36 dice_list = @randomizer.roll_barabara(counts, 6).sort
  162. 36 all_dice = (dice_list + carry).sort
  163. 36 filtered = select_uniqs(all_dice)
  164. 36 then: 22 else: 14 title = carry.empty? ? translate("BeginningIdol.PD.paformance") : translate("BeginningIdol.PD.symphony")
  165. result =
  166. 36 then: 22 if carry.empty?
  167. 22 result_performance(filtered, modifier, all_dice)
  168. else: 14 else
  169. 14 result_symphony(filtered, modifier)
  170. end
  171. sequence = [
  172. 36 title,
  173. format_dice_list(dice_list, carry, modifier),
  174. result,
  175. ]
  176. 36 return sequence.join(" > ")
  177. end
  178. 1 def select_uniqs(dice_list)
  179. 36 dice_list.group_by(&:itself).to_a
  180. 134 .select { |_, arr| arr.size == 1 }
  181. 98 .map { |dice, _| dice }
  182. .sort
  183. end
  184. 1 def format_dice_list(dice_list, carry, modifier)
  185. 36 then: 22 if carry.empty?
  186. 22 "[#{dice_list.join(',')}]#{Format.modifier(modifier)}"
  187. else: 14 else
  188. 14 "[#{dice_list.join(',')}],[#{carry.join(',')}]#{Format.modifier(modifier)}"
  189. end
  190. end
  191. 1 def result_performance(list, modifier, all_list)
  192. 22 then: 4 if list.empty?
  193. 4 else: 18 format(translate("BeginningIdol.PD.miracle"), value: modifier + 10)
  194. 18 then: 4 elsif list == [1, 2, 3, 4, 5, 6]
  195. 4 else: 14 format(translate("BeginningIdol.PD.perfect_miracle"), value: modifier + 30)
  196. 14 then: 12 elsif list.size != all_list.size
  197. 12 "[#{list.join(',')}]#{Format.modifier(modifier)} > #{list.sum() + modifier}"
  198. else: 2 else
  199. 2 (list.sum() + modifier).to_s
  200. end
  201. end
  202. 1 def result_symphony(list, modifier)
  203. 14 then: 4 if list.empty?
  204. 4 else: 10 format(translate("BeginningIdol.PD.miracle_synchro"), value: modifier + 15)
  205. 10 then: 6 elsif list == [1, 2, 3, 4, 5, 6]
  206. 6 perfect_miracle = format(translate("BeginningIdol.PD.perfect_miracle"), value: modifier + 30)
  207. 6 "[#{list.join(',')}]#{Format.modifier(modifier)} > #{perfect_miracle}"
  208. else: 4 else
  209. 4 "[#{list.join(',')}]#{Format.modifier(modifier)} > #{list.sum() + modifier}"
  210. end
  211. end
  212. end
  213. end
  214. end

lib/bcdice/game_system/BeginningIdol2022.rb

100.0% lines covered

100.0% branches covered

86 relevant lines. 86 lines covered and 0 lines missed.
30 total branches, 30 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BeginningIdol2022 < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'BeginningIdol2022'
  7. # ゲームシステム名
  8. 1 NAME = 'ビギニングアイドル(2022年改訂版)'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ひきにんくあいとる2022'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. これは、2022年に大判サイズで発売された『駆け出しアイドルRPG ビギニングアイドル 基本ルールブック』に対応したコマンドです。
  14. ・行為判定 BIn@c#f+m>=t
  15.  nD6をダイスロールし、行為判定に成功したかを出力します。スペシャルとファンブルの判定も行います。
  16.   n: ダイス数(省略時 2)
  17.   c: スペシャル値(省略時 12)
  18.   f: ファンブル値(省略時 2)
  19.   m: 修正値(省略可)
  20.   t: 目標値
  21. ・パフォーマンス判定 PDn+m
  22.  nD6をダイスロールし、パフォーマンス値を出力します。パーフェクトミラクルとミラクルの判定も行います。
  23.   n: ダイス数
  24.   m: 修正値(省略可)
  25. ・シンフォニー xxxPDn+m
  26.  nD6をダイスロールし、場に残っているダイスを加味してパフォーマンス値を出力します。
  27.  パーフェクトミラクルとミラクルシンクロの判定も行います。
  28.   xxx: 場に残っているダイスの出目を列挙したもの
  29.   n: ダイス数
  30.   m: 修正値(省略可)
  31. INFO_MESSAGE_TEXT
  32. 1 def initialize(command)
  33. 40 super(command)
  34. 40 @sort_add_dice = true
  35. 40 @d66_sort_type = D66SortType::ASC
  36. end
  37. 1 register_prefix("BI", "PD", "[1-6]+PD")
  38. 1 def eval_game_system_specific_command(command)
  39. 40 roll_skill_check(command) || roll_performance_check(command) || roll_symphony_check(command)
  40. end
  41. 1 private
  42. # 行為判定
  43. 1 def roll_skill_check(command)
  44. 40 parser = Command::Parser.new("BI", round_type: @round_type)
  45. .enable_suffix_number
  46. .enable_critical
  47. .enable_fumble
  48. .restrict_cmp_op_to(:>=)
  49. 40 parsed = parser.parse(command)
  50. 40 else: 15 then: 25 unless parsed
  51. 25 return nil
  52. end
  53. 15 dice_times = parsed.suffix_number || 2
  54. 15 critical = parsed.critical || 12
  55. 15 fumble = parsed.fumble || 2
  56. 15 dice_list = @randomizer.roll_barabara(dice_times, 6).sort()
  57. 15 dice_total = dice_list.sum()
  58. 15 is_critical = dice_total >= critical
  59. 15 is_fumble = !is_critical && dice_total <= fumble
  60. 15 total = dice_total + parsed.modify_number
  61. result =
  62. 15 then: 5 if is_critical
  63. 5 else: 10 Result.critical("スペシャル(PCは【思い出】を1つ獲得する)")
  64. 10 then: 3 elsif is_fumble
  65. 3 else: 7 Result.fumble("ファンブル(【思い出】を1つ獲得し、ファンブル表を振る)")
  66. 7 then: 5 elsif total >= parsed.target_number
  67. 5 Result.success("成功")
  68. else: 2 else
  69. 2 Result.failure("失敗")
  70. end
  71. 15 result.text = "(#{parsed}) > #{dice_total}[#{dice_list.join(',')}]#{Format.modifier(parsed.modify_number)} > #{total} > #{result.text}"
  72. 15 return result
  73. end
  74. # パフォーマンス判定
  75. 1 def roll_performance_check(command)
  76. 25 m = /^PD(\d+)([+-]\d+)?$/.match(command)
  77. 25 else: 17 then: 8 unless m
  78. 8 return nil
  79. end
  80. 17 suffix_number = m[1].to_i
  81. 17 modifier = m[2].to_i
  82. 17 is_extension = suffix_number >= 7
  83. 17 then: 7 else: 10 dice_times = is_extension ? 6 : suffix_number
  84. 17 then: 7 else: 10 extension_bonus = is_extension ? suffix_number - dice_times : 0
  85. 17 then: 1 else: 16 if dice_times <= 0
  86. 1 return nil
  87. end
  88. 16 dice_list = @randomizer.roll_barabara(dice_times, 6).sort()
  89. 16 uniqed = select_uniqs(dice_list).sort()
  90. 16 is_perfect_miracle = uniqed == [1, 2, 3, 4, 5, 6]
  91. 16 is_miracle = uniqed.empty?
  92. result_label =
  93. 16 then: 4 if is_perfect_miracle
  94. 4 else: 12 "【パーフェクトミラクル】#{30 + extension_bonus + modifier}"
  95. 12 then: 4 elsif is_miracle
  96. 4 "【ミラクル】#{10 + extension_bonus + modifier}"
  97. else: 8 else
  98. 8 (uniqed.sum() + extension_bonus + modifier).to_s
  99. end
  100. 16 then: 7 else: 9 if is_extension
  101. 7 result_label += " (エクステンション: #{extension_bonus}個まで振りなおし可能)"
  102. end
  103. 16 Result.new.tap do |result|
  104. 16 result.critical = is_perfect_miracle || is_miracle
  105. 16 result.text = [
  106. "(#{command})",
  107. "パフォーマンス判定",
  108. "[#{dice_list.join(',')}]#{Format.modifier(extension_bonus)}#{Format.modifier(modifier)}",
  109. 16 then: 11 else: 5 ("[#{uniqed.join(',')}]#{Format.modifier(extension_bonus)}#{Format.modifier(modifier)}" if dice_list.size != uniqed.size),
  110. result_label,
  111. ].compact.join(" > ")
  112. end
  113. end
  114. 1 def select_uniqs(array)
  115. # TODO: Ruby 2.7以降のみサポートするようになった場合に Enumerable#tally で書く
  116. 22 array.group_by(&:itself)
  117. .to_a
  118. 96 .select { |_, arr| arr.size == 1 }
  119. 61 .map { |key, _| key }
  120. end
  121. # シンフォニー
  122. 1 def roll_symphony_check(command)
  123. 9 m = /^([1-6]+)PD([1-6])([+-]\d+)?$/.match(command)
  124. 9 else: 6 then: 3 unless m
  125. 3 return nil
  126. end
  127. 6 carries = m[1].chars.map(&:to_i).sort()
  128. 6 dice_times = m[2].to_i
  129. 6 modifier = m[3].to_i
  130. 6 dice_list = @randomizer.roll_barabara(dice_times, 6).sort()
  131. 6 uniqed = select_uniqs(carries + dice_list).sort()
  132. 6 is_perfect_miracle = uniqed == [1, 2, 3, 4, 5, 6]
  133. 6 is_miracle_synchro = uniqed.empty?
  134. result_label =
  135. 6 then: 2 if is_perfect_miracle
  136. 2 else: 4 "【パーフェクトミラクル】#{30 + modifier}"
  137. 4 then: 2 elsif is_miracle_synchro
  138. 2 "【ミラクルシンクロ】#{20 + modifier}"
  139. else: 2 else
  140. 2 (uniqed.sum() + modifier).to_s
  141. end
  142. 6 Result.new.tap do |result|
  143. 6 result.critical = is_perfect_miracle || is_miracle_synchro
  144. 6 result.text = [
  145. "(#{command})",
  146. "シンフォニー",
  147. "[#{carries.join(',')}],[#{dice_list.join(',')}]#{Format.modifier(modifier)}",
  148. "[#{uniqed.join(',')}]#{Format.modifier(modifier)}",
  149. result_label,
  150. ].join(" > ")
  151. end
  152. end
  153. end
  154. end
  155. end

lib/bcdice/game_system/BeginningIdol_Korean.rb

100.0% lines covered

100.0% branches covered

17 relevant lines. 17 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/BeginningIdol"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class BeginningIdol_Korean < BeginningIdol
  6. # ゲームシステムの識別子
  7. 1 ID = 'BeginningIdol:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '비기닝 아이돌'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:비기닝 아이돌'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・퍼포먼스 [r]PDn[+m/-m](r:남은 주사위 눈 n:굴릴 갯수 m:수정치)
  15. ・월드세팅 업무표 BWT:대형 연예 프로덕션 LWT:약소 연예 프로덕션
  16.  TWT:라이브 시어터 CWT:아이돌 부 LO[n]:로컬 아이돌(n:찬스)
  17.  SU:열정의 여름 WI:온기의 겨울 NA:대자연 GA:女学園 BA:アカデミー
  18. ・업무표 WT VA:버라이어티 MU:음악 관련 DR:드라마 관련
  19.  VI:비주얼 관련 SP:스포츠 CHR:크리스마스 PAR:파트너 관련
  20. ・특기 리스트 AN:動物 MOV:映画 FA:ファンタジー
  21. ・ハプニング表 HA
  22. ・特技リスト AT[n](n:分野No.)
  23. ・아이돌 스킬 습득표 SGT:챌린지 걸즈 RS:로드 투 프린스
  24. ・변조 BT[n](n:주사위눈)
  25. ・아이템 IT[n](n:보유 갯수)
  26. ・アクセサリー ACT:種別決定 ACB:ブランド決定 ACE:効果表
  27. ・의상 DT:챌린지 걸즈 RC:로드 투 프린스 FC:フォーチュンスターズ
  28. ・엉망진창 표 LUR:로컬 아이돌 SUR:정열의 여름 WUR:온기의 겨울
  29.  NUR:대자연 GUR:女学園 BUR:アカデミー
  30. ・센터 룰 HW:역풍 씬표 FL:신출내기 씬표 LN:고독표
  31.  マイスキル【MS:名前決定 MSE:効果表】 演出表【ST FST:ファンタジー】
  32. ・합숙 룰 산책표 【SH:쇼핑몰 MO:산 SEA:바다 SPA:온천】
  33.  TN:야밤의 대화 시츄에이션 성장표 【CG:커먼 GG:골드】
  34. ・작사표 CHO SCH:정열의 여름 WCH:온기의 겨울 NCH:대자연
  35. ・캐릭터 공백표 CBT:챌린지 걸즈 RCB:로드 투 프린스
  36. ・취미 공백표 HBT:챌린지 걸즈 RHB:로드 투 프린스
  37. ・마스코트 폭주표 RU
  38. ・버스트 타임 nC:バーストタイム(n:온도) BU:バースト表
  39. ・攻撃 n[S]A[r][+m/-m](n:振る数 S:失敗しない r:取り除く出目 m:修正値)
  40. ・かんたんパーソン表 SIP
  41. ・회장표
  42.  BVT:대형 예능 프로덕션 LVT:약소 예능 프로덕션 TVT:라이브 시어터 CVT:아이돌 부
  43. ・장소표
  44.  BST:대형 예능 프로덕션 LST:약소 예능 프로덕션 TST:라이브 시어터 CST:아이돌 부
  45. ・프레셔 종류 결정표
  46.  BPT:대형 예능 프로덕션 LPT:약소 예능 프로덕션 TPT:라이브 시어터 CPT:아이돌 부
  47. ・도구표
  48.  BIT:대형 예능 프로덕션 LIT:약소 예능 프로덕션 TIT:라이브 시어터 CIT:아이돌 부
  49. []内は省略可 D66 다이스가 존재
  50. INFO_MESSAGE_TEXT
  51. 1 register_prefix_from_super_class()
  52. 1 def initialize(command)
  53. 196 super(command)
  54. 196 @locale = :ko_kr
  55. end
  56. 1 TABLES = translate_tables(:ko_kr)
  57. 1 BAD_STATUS_TABLE = BadStatusTable.new(:ko_kr)
  58. 1 LOCAL_WORK_TABLE = translate_local_work_table(:ko_kr)
  59. 1 ITEM_TABLE = ItemTable.new(:ko_kr)
  60. 1 SKILL_TABLE = translate_skill_table(:ko_kr)
  61. end
  62. end
  63. end

lib/bcdice/game_system/BlackJacket.rb

98.7% lines covered

96.43% branches covered

77 relevant lines. 76 lines covered and 1 lines missed.
28 total branches, 27 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/dice_table/range_table'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class BlackJacket < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'BlackJacket'
  8. # ゲームシステム名
  9. 1 NAME = 'ブラックジャケットRPG'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'ふらつくしあけつとRPG'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・行為判定(BJx)
  15.  x:成功率
  16.  例)BJ80
  17.  クリティカル、ファンブルの自動的判定を行います。
  18.  「BJ50+20-30」のように加減算記述も可能。
  19.  成功率は上限100%、下限0%
  20. ・デスチャート(DCxY)
  21.  x:チャートの種類。肉体:DCL、精神:DCS、環境:DCC
  22.  Y=マイナス値
  23.  例)DCL5:ライフが -5 の判定
  24.    DCS3:サニティーが -3 の判定
  25.    DCC0:クレジット 0 の判定
  26. ・チャレンジ・ペナルティ・チャート(CPC)
  27. ・サイドトラック・チャート(STC)
  28. INFO_MESSAGE_TEXT
  29. 1 def eval_game_system_specific_command(command)
  30. 87 resolute_action(command) || roll_death_chart(command) || roll_tables(command, TABLES)
  31. end
  32. 1 private
  33. 1 def resolute_action(command)
  34. 87 m = /^BJ(\d+([+-]\d+)*)$/.match(command)
  35. 87 else: 38 then: 49 unless m
  36. 49 return nil
  37. end
  38. 38 success_rate = ArithmeticEvaluator.eval(m[1])
  39. 38 roll_result, dice10, dice01 = roll_d100
  40. 38 roll_result_text = format('%02d', roll_result)
  41. 38 result = action_result(roll_result, dice10, dice01, success_rate)
  42. sequence = [
  43. 38 "行為判定(成功率:#{success_rate}%)",
  44. "1D100[#{dice10},#{dice01}]=#{roll_result_text}",
  45. roll_result_text.to_s,
  46. result.text
  47. ]
  48. 38 result.text = sequence.join(" > ")
  49. 38 result
  50. end
  51. 1 SUCCESS_STR = "成功"
  52. 1 FAILURE_STR = "失敗"
  53. 1 CRITICAL_STR = (SUCCESS_STR + " > クリティカル! パワーの代償1/2").freeze
  54. 1 FUMBLE_STR = (FAILURE_STR + " > ファンブル! パワーの代償2倍&振り直し不可").freeze
  55. 1 MISERY_STR = (FAILURE_STR + " > ミザリー! パワーの代償2倍&振り直し不可").freeze
  56. 1 def action_result(total, tens, ones, success_rate)
  57. 38 then: 6 if total == 100
  58. 6 else: 32 Result.fumble(MISERY_STR)
  59. 32 then: 1 elsif success_rate <= 0
  60. 1 else: 31 Result.fumble(FUMBLE_STR)
  61. 31 then: 4 elsif total <= success_rate - 100
  62. 4 else: 27 Result.critical(CRITICAL_STR)
  63. 27 then: 8 elsif tens == ones
  64. 8 then: 6 if total <= success_rate
  65. 6 Result.critical(CRITICAL_STR)
  66. else: 2 else
  67. 2 Result.fumble(FUMBLE_STR)
  68. else: 19 end
  69. 19 then: 15 elsif total <= success_rate
  70. 15 Result.success(SUCCESS_STR)
  71. else: 4 else
  72. 4 Result.failure(FAILURE_STR)
  73. end
  74. end
  75. 1 def roll_d100
  76. 38 dice10 = @randomizer.roll_once(10)
  77. 38 then: 12 else: 26 dice10 = 0 if dice10 == 10
  78. 38 dice01 = @randomizer.roll_once(10)
  79. 38 then: 4 else: 34 dice01 = 0 if dice01 == 10
  80. 38 roll_result = dice10 * 10 + dice01
  81. 38 then: 6 else: 32 roll_result = 100 if roll_result == 0
  82. 38 return roll_result, dice10, dice01
  83. end
  84. 1 class DeathChart
  85. 1 def initialize(name, chart)
  86. 3 @name = name
  87. 3 @chart = chart.freeze
  88. 3 then: 0 else: 3 if @chart.size != 11
  89. raise ArgumentError, "unexpected chart size #{name.inspect} (given #{@chart.size}, expected 11)"
  90. end
  91. end
  92. # @param randomizer [Randomizer]
  93. # @param minus_score [Integer]
  94. # @return [String]
  95. 1 def roll(randomizer, minus_score)
  96. 44 dice = randomizer.roll_once(10)
  97. 44 key_number = dice + minus_score
  98. 44 key_text, chosen = at(key_number)
  99. 44 return "デスチャート(#{@name})[マイナス値:#{minus_score} + 1D10(->#{dice}) = #{key_number}] > #{key_text} : #{chosen}"
  100. end
  101. 1 private
  102. # key_numberの10から20がindexの0から10に対応する
  103. 1 def at(key_number)
  104. 44 then: 4 if key_number < 10
  105. 4 else: 40 ["10以下", @chart.first]
  106. 40 then: 3 elsif key_number > 20
  107. 3 ["20以上", @chart.last]
  108. else: 37 else
  109. 37 [key_number.to_s, @chart[key_number - 10]]
  110. end
  111. end
  112. end
  113. 1 def roll_death_chart(command)
  114. 49 m = /^DC([LSC])(\d+)$/i.match(command)
  115. 49 else: 44 then: 5 unless m
  116. 5 return m
  117. end
  118. 44 chart = DEATH_CHARTS[m[1]]
  119. 44 minus_score = m[2].to_i
  120. 44 return chart.roll(@randomizer, minus_score)
  121. end
  122. DEATH_CHARTS = {
  123. 1 'L' => DeathChart.new(
  124. '肉体',
  125. [
  126. "何も無し。キミは奇跡的に一命を取り留めた。闘いは続く。",
  127. "激痛が走る。以後、イベント終了時まで、全ての判定の成功率-10%。",
  128. "もう、体が動かない……。キミは[硬直2]を受ける。",
  129. "渾身の一撃!! キミは〈生存〉判定を行なう。失敗した場合、[死亡]する。",
  130. "突然、目の前が真っ暗になった。キミは[気絶2]を受ける。",
  131. "以後、イベント終了時まで、全ての判定の成功率-20%。",
  132. "記録的一撃!! キミは〈生存〉-20%の判定を行なう。失敗した場合、[死亡]する。",
  133. "生きているのか死んでいるのか。キミは[瀕死2]を受ける。",
  134. "叙事詩的一撃!! キミは〈生存〉-30%の判定を行なう。失敗した場合、[死亡]する。",
  135. "以後、イベント終了時まで、全ての判定の成功率-30%。",
  136. "神話的一撃!! キミは宙を舞って三回転ほどした後、地面に叩きつけられる。見るも無惨な姿。肉体は原型を留めていない(キミは[死亡]した)。",
  137. ]
  138. ),
  139. 'S' => DeathChart.new(
  140. '精神',
  141. [
  142. "何も無し。キミは歯を食いしばってストレスに耐えた。",
  143. "以後、イベント終了時まで、全ての判定の成功率-10%。",
  144. "云い知れぬ恐怖がキミを襲う。キミは[恐怖2]を受ける。",
  145. "とても傷ついた。キミは〈意思〉判定を行なう。失敗した場合、[絶望]してNPCとなる。",
  146. "キミは意識を失った。キミは[気絶2]を受ける。",
  147. "以後、イベント終了時まで、全ての判定の成功率-20%。",
  148. "信じる者にだまされたような痛み。キミは〈意思〉-20%の判定を行なう。失敗した場合、[絶望]してNPCとなる。",
  149. "仲間に裏切られたのかも知れない。キミは[混乱2]を受ける。",
  150. "あまりに残酷な現実。キミは〈意思〉-30%の判定を行なう。失敗した場合、[絶望]してNPCとなる。",
  151. "以後、イベント終了時まで、全ての判定の成功率-30%。",
  152. "宇宙開闢の理に触れるも、それは人類の認識限界を超える何かであった。キミは[絶望]し、以後NPCとなる。",
  153. ]
  154. ),
  155. 'C' => DeathChart.new(
  156. '環境',
  157. [
  158. "何も無し。キミは黒い噂を握りつぶした。",
  159. "以後、イベント終了時まで、全ての判定の成功率-10%。",
  160. "ピンチ! 以後、ラウンド終了時まで、キミはカルマを使用できない。",
  161. "悪い噂が流れる。キミは〈交渉〉判定を行なう。失敗した場合、キミは仲間からの信頼を失って[無縁]され、NPCとなる。",
  162. "以後、イベント終了時まで、代償にクレジットを消費するパワーを使用できない。",
  163. "キミの悪評が世間に知れ渡る。協力者からの支援が打ち切られる。以後、シナリオ終了時まで、全ての判定の成功率-20%。",
  164. "裏切り!! キミは〈経済〉-20%の判定を行なう。失敗した場合、キミは周囲からの信頼を失い、[無縁]され、NPCとなる。",
  165. "以後、シナリオ終了時まで、【環境】系の技能のレベルがすべて0となる。",
  166. "捏造報道? 身に覚えのない背信行為がスクープとして報道される。キミは〈心理〉-30%の判定を行なう。失敗した場合、キミは人としての尊厳を失い、[無縁]を受ける。",
  167. "以後、イベント終了時まで、全ての判定の成功率-30%。",
  168. "キミの名は史上最悪の汚点として歴史に刻まれる。もはらキミを信じる仲間はなく、キミを助ける社会もない。キミは[無縁]され、以後NPCとなる。",
  169. ]
  170. )
  171. }.freeze
  172. TABLES = {
  173. 1 "CPC" => DiceTable::Table.new(
  174. "チャレンジ・ペナルティ・チャート",
  175. "1D10",
  176. [
  177. "逝去\n助けるべきNPC(ヒロインなど)が死亡する。",
  178. "黒星\n敵が目的を成就し、事件はPCの敗北で終了する。そのまま余韻フェイズへ。",
  179. "活性\n敵のボスのライフを2倍にしたうえで決戦フェイズを開始する。",
  180. "攻勢\n敵ボスの与ダメージに+2D6の修正を与えたうえで決戦フェイズを開始する。",
  181. "大挙\n敵の数(ボス以外)を2倍にしたうえで決戦フェイズを開始する。",
  182. "暗黒\nすべてのエリアを[暗闇]にしたうえで決戦フェイズを開始する。",
  183. "猛火\n2つの戦場エリアを[ダメージゾーン2]にして、決戦フェイズを開始する。",
  184. "伏兵\n敵の半分をエリア1とエリア2に移動させた状態で決戦フェイズを開始する。",
  185. "満腹\nボス以外の敵のライフをすべて2倍にしたうえで決戦フェイズを開始する。",
  186. "封印\n決戦フェイズの間、PCはカルマを使用できない。決戦フェイズを開始する。"
  187. ]
  188. ),
  189. "STC" => DiceTable::Table.new(
  190. "サイドトラック・チャート",
  191. "1D10",
  192. [
  193. "邂逅\n偶然、NPCと出会う。どのNPCが現れるかはGMが決定すること。",
  194. "事故\n交通事故に出くわす。周囲ではパニックが起きているかも知れない。",
  195. "午睡\n強烈な睡魔に襲われる。まさか、新手のヴィランの能力か?",
  196. "告白\nNPCのひとりから、今まで秘めていた思いを吐露される。",
  197. "設定\n新たな設定が明かされる。実はNPCの父だったとか、生来目が見えん、とか。",
  198. "刺客\n何者かから攻撃を受ける。第3勢力か?",
  199. "会敵\n偶然、仇敵のひとりと出くわす。追うべきか? 無視すべきか?",
  200. "不審\n怪しい人物を見かける。追うべきか? 無視すべきか?",
  201. "遭遇\nシナリオと関係のないヴィラン組織と遭遇する。",
  202. "平和\n特に何も起きなかった。",
  203. ]
  204. ),
  205. }.freeze
  206. 1 register_prefix(
  207. 'BJ',
  208. 'DC[LSC]',
  209. TABLES.keys
  210. )
  211. end
  212. end
  213. end

lib/bcdice/game_system/BlackJacket_Korean.rb

98.7% lines covered

96.43% branches covered

77 relevant lines. 76 lines covered and 1 lines missed.
28 total branches, 27 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/dice_table/range_table'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class BlackJacket_Korean < BlackJacket
  6. # ゲームシステムの識別子
  7. 1 ID = 'BlackJacket:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '블랙재킷RPG'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:블랙재킷RPG'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・행위 판정(BJx)
  15.  x:성공률
  16.  예)BJ80
  17.  크리티컬,펌블 여부는 자동으로 판정합니다.
  18.  「BJ50+20-30」처럼 값을 가감하여 기재할 수 있습니다.
  19.  성공률의 상한은 100%、하한은 0% 입니다.
  20. ・데스 차트 (DCxY)
  21.  x:차트 종류. 육체:DCL, 정신:DCS, 환경:DCC
  22.  Y=마이너스 값
  23.  예)DCL5:라이프 마이너스 값 5 + 1D10 판정
  24.    DCS3:새니티 마이너스 값 3 + 1D10 판정
  25.    DCC0:크레딧 마이너스 값 0 + 1D10 판정
  26. ・챌린지・패널티 차트(CPC)
  27. ・사이드 트랙 차트(STC)
  28. INFO_MESSAGE_TEXT
  29. 1 def eval_game_system_specific_command(command)
  30. 87 resolute_action(command) || roll_death_chart(command) || roll_tables(command, TABLES)
  31. end
  32. 1 private
  33. 1 def resolute_action(command)
  34. 87 m = /^BJ(\d+([+-]\d+)*)$/.match(command)
  35. 87 else: 38 then: 49 unless m
  36. 49 return nil
  37. end
  38. 38 success_rate = ArithmeticEvaluator.eval(m[1])
  39. 38 roll_result, dice10, dice01 = roll_d100
  40. 38 roll_result_text = format('%02d', roll_result)
  41. 38 result = action_result(roll_result, dice10, dice01, success_rate)
  42. sequence = [
  43. 38 "행위판정(성공률:#{success_rate}%)",
  44. "1D100[#{dice10},#{dice01}]=#{roll_result_text}",
  45. roll_result_text.to_s,
  46. result.text
  47. ]
  48. 38 result.text = sequence.join(" > ")
  49. 38 result
  50. end
  51. 1 SUCCESS_STR = "성공"
  52. 1 FAILURE_STR = "실패"
  53. 1 CRITICAL_STR = (SUCCESS_STR + " > 크리티컬! 파워의 대가(코스트) 절반으로 감소").freeze
  54. 1 FUMBLE_STR = (FAILURE_STR + " > 펌블! 파워의 대가(코스트) 2배 & 재굴림 불가").freeze
  55. 1 MISERY_STR = (FAILURE_STR + " > 미저리! 파워의 대가(코스트) 2배 & 재굴림 불가").freeze
  56. 1 def action_result(total, tens, ones, success_rate)
  57. 38 then: 6 if total == 100
  58. 6 else: 32 Result.fumble(MISERY_STR)
  59. 32 then: 1 elsif success_rate <= 0
  60. 1 else: 31 Result.fumble(FUMBLE_STR)
  61. 31 then: 4 elsif total <= success_rate - 100
  62. 4 else: 27 Result.critical(CRITICAL_STR)
  63. 27 then: 8 elsif tens == ones
  64. 8 then: 6 if total <= success_rate
  65. 6 Result.critical(CRITICAL_STR)
  66. else: 2 else
  67. 2 Result.fumble(FUMBLE_STR)
  68. else: 19 end
  69. 19 then: 15 elsif total <= success_rate
  70. 15 Result.success(SUCCESS_STR)
  71. else: 4 else
  72. 4 Result.failure(FAILURE_STR)
  73. end
  74. end
  75. 1 def roll_d100
  76. 38 dice10 = @randomizer.roll_once(10)
  77. 38 then: 12 else: 26 dice10 = 0 if dice10 == 10
  78. 38 dice01 = @randomizer.roll_once(10)
  79. 38 then: 4 else: 34 dice01 = 0 if dice01 == 10
  80. 38 roll_result = dice10 * 10 + dice01
  81. 38 then: 6 else: 32 roll_result = 100 if roll_result == 0
  82. 38 return roll_result, dice10, dice01
  83. end
  84. 1 class DeathChart
  85. 1 def initialize(name, chart)
  86. 3 @name = name
  87. 3 @chart = chart.freeze
  88. 3 then: 0 else: 3 if @chart.size != 11
  89. raise ArgumentError, "unexpected chart size #{name.inspect} (given #{@chart.size}, expected 11)"
  90. end
  91. end
  92. # @param randomizer [Randomizer]
  93. # @param minus_score [Integer]
  94. # @return [String]
  95. 1 def roll(randomizer, minus_score)
  96. 44 dice = randomizer.roll_once(10)
  97. 44 key_number = dice + minus_score
  98. 44 key_text, chosen = at(key_number)
  99. 44 return "데스 차트(#{@name})[마이너스 값:#{minus_score} + 1D10(->#{dice}) = #{key_number}] > #{key_text} : #{chosen}"
  100. end
  101. 1 private
  102. # key_numberの10から20がindexの0から10に対応する
  103. 1 def at(key_number)
  104. 44 then: 4 if key_number < 10
  105. 4 else: 40 ["10이하", @chart.first]
  106. 40 then: 3 elsif key_number > 20
  107. 3 ["20이상", @chart.last]
  108. else: 37 else
  109. 37 [key_number.to_s, @chart[key_number - 10]]
  110. end
  111. end
  112. end
  113. 1 def roll_death_chart(command)
  114. 49 m = /^DC([LSC])(\d+)$/i.match(command)
  115. 49 else: 44 then: 5 unless m
  116. 5 return m
  117. end
  118. 44 chart = DEATH_CHARTS[m[1]]
  119. 44 minus_score = m[2].to_i
  120. 44 return chart.roll(@randomizer, minus_score)
  121. end
  122. DEATH_CHARTS = {
  123. 1 'L' => DeathChart.new(
  124. '육체',
  125. [
  126. "효과 없음. 당신은 기적적으로 목숨을 건졌다. 싸움은 계속된다.",
  127. "격한 통증을 느낀다. 이후 이벤트가 끝날 때까지 모든 판정의 성공률에 -10%.",
  128. "더이상 몸이 움직이지 않는다…… 당신은 [경직 2]를 받는다.",
  129. "혼신의 일격!! 당신은 〈생존〉 판정을 한다. 실패할 경우 [사망]한다.",
  130. "갑자기 눈앞이 캄캄해진다. 당신은 [기절 2]를 받는다.",
  131. "이후, 이벤트 종료까지 모든 판정의 성공률 -20%.",
  132. "기록적인 일격!! 당신은 〈생존〉 -20% 으로 판정한다. 실패할 경우 [사망]한다.",
  133. "사느냐 죽느냐. 당신은 [빈사 2]를 받는다.",
  134. "역사에 한 획을 그을 일격!! 당신은 <생존> -30% 으로 판정한다. 실패할 경우 [사망]한다.",
  135. "이후, 이벤트 종료 시까지 모든 판정의 성공률 -30%.",
  136. "신화적 일격!! 공중에서 세 바퀴 정도 회전한 후 땅바닥에 내동댕이쳐진다. 보기에도 끔찍한 모습. 육체는 원형을 유지하지 못했다. 당신은 [사망]한다.",
  137. ]
  138. ),
  139. 'S' => DeathChart.new(
  140. '정신',
  141. [
  142. "효과 없음. 당신은 이를 악물고 스트레스를 견뎌냈다.",
  143. "이후, 이벤트 종료 시까지 모든 판정의 성공률 -10%.",
  144. "말할 수 없는 공포가 당신을 엄습한다. 당신은 [공포 2]를 받는다.",
  145. "상처를 많이 받았다. 당신은 〈의지〉 판정을 한다. 실패할 경우 [절망] 상태가 되어서 NPC가 된다.",
  146. "의식을 잃었다. 당신은 [기절 2]를 받는다.",
  147. "이후, 이벤트 종료 시까지 모든 판정의 성공률 -20%.",
  148. "신뢰했던 자에게 속은 아픔. 당신은 〈의지〉 -20% 으로 판정한다. 실패할 경우, [절망] 상태가 되어서 NPC가 된다.",
  149. "동료에게 배신 당한 것일지도 모른다. 당신은 [혼란 2]를 받는다.",
  150. "너무나 참혹한 현실. 당신은 〈의지〉 -30% 으로 판정한다. 실패할 경우 [절망] 상태가 되어서 NPC가 된다.",
  151. "이후, 이벤트 종료 시까지 모든 판정의 성공률 -30%.",
  152. "천지개벽의 이치 그 이상. 그것은 인류의 인식한계를 뛰어넘는 무언가였다. 당신은 [절망] 상태가 된 후 NPC가 된다.",
  153. ]
  154. ),
  155. 'C' => DeathChart.new(
  156. '환경',
  157. [
  158. "효과 없음. 당신은 뒤숭숭한 소문을 무시했다.",
  159. "이후, 이벤트 종료 시까지 모든 판정의 성공률 -10%.",
  160. "위험한 상태! 이후, 라운드 종료 시까지 당신은 카르마를 사용할 수 없다.",
  161. "나쁜 소문이 돈다. 당신은 〈교섭〉 판정을 한다. 실패할 경우 당신은 동료들의 신뢰를 잃고 [무연고] 상태가 된 후 NPC가 된다.",
  162. "이후, 시나리오 종료 시까지 대가(코스트)에 크레딧을 소비하는 파워를 사용할 수 없다.",
  163. "당신의 악평이 세상에 널리 알려진다. 협력자로부터의 지원이 중단된다. 이후 시나리오 종료 시까지 모든 판정의 성공률 -20%.",
  164. "배신!! 당신은 〈경제〉 -20% 으로 판정한다. 실패할 경우 당신은 주위로부터 신용을 잃고, [무연고] 상태가 되어 NPC가 된다.",
  165. "이후, 시나리오 종료 시까지 【환경】 계열의 기능 레벨이 모두 0이 된다.",
  166. "날조 보도? 기억나지 않는 배신 행위가 특종으로 보도된다. 당신은 〈심리〉 -30% 으로 판정한다. 실패할 경우 당신은 인간으로서의 존엄성을 잃고, [무연고]가 된다.",
  167. "이후, 이벤트 종료 시까지 모든 판정 성공률 -30%.",
  168. "당신의 이름은 사상 최악의 오점으로 영원히 역사에 새겨진다. 이제 당신을 믿는 동료는 없고 당신을 돕는 사회도 없다. 당신은 [무연고] 상태가 된 후 NPC가 된다.",
  169. ]
  170. )
  171. }.freeze
  172. TABLES = {
  173. 1 "CPC" => DiceTable::Table.new(
  174. "챌린지・패널티 차트",
  175. "1D10",
  176. [
  177. "사망\n도와야 할 NPC (히로인 등)가 사망한다.",
  178. "검은 별\n적이 목적을 성취하고, 사건은 PC의 패배로 끝난다. 그대로 여운 페이즈로 넘어갈 것.",
  179. "활성\n적 보스의 라이프를 2배로 한 다음 결전 페이즈를 개시한다.",
  180. "공세\n적 보스의 대미지에 +2D6의 수정을 준 후 결전 페이즈를 개시한다.",
  181. "대거\n적의 수(보스 제외)를 2배로 한 후 결전 페이즈를 개시한다.",
  182. "암흑\n모든 에리어(구역)을 [어둠]으로 만든 다음 결전 페이즈를 개시한다.",
  183. "맹화\n전투 에리어(구역) 2개를 [대미지 존 2]로 취급한 후, 결전 페이즈를 개시한다.",
  184. "복병\n적의 절반을 에리어(구역) 1과 에리어(구역) 2로 이동시킨 후, 결전 페이즈를 개시한다.",
  185. "만복\n보스 이외의 적의 라이프를 모두 2배로 한 다음, 결전 페이즈를 개시한다.",
  186. "봉인\nPC는 결전 페이즈 동안 카르마를 사용할 수 없다. 결전 페이즈를 개시한다."
  187. ]
  188. ),
  189. "STC" => DiceTable::Table.new(
  190. "사이드 트랙 차트",
  191. "1D10",
  192. [
  193. "해후\n우연히 NPC와 만난다. 어떤 NPC가 나타날지는 GM이 결정한다.",
  194. "사고\교통사고를 당한다. 주변에서 패닉이 일어나고 있을지도 모른다.",
  195. "낮잠\n지독한 졸음이 몰려온다. 설마, 신참 빌런의 능력인가?",
  196. "고백\nNPC 한 명이 지금까지 간직하고 있던 마음을 당신에게 고백한다.",
  197. "설정\n새로운 설정이 밝혀진다. 사실은 NPC의 아버지였다든가, 선천적으로 눈이 보이지 않는다든가.",
  198. "자객\n누군가로부터 공격을 받는다. 제3세력인가?",
  199. "불청객\n우연히 원수 한 명과 마주친다. 상황에 따라서 바로 전투가 발생할지도 모른다.",
  200. "의심\n수상한 사람을 눈치챘다. 따라가야 하나? 무시해야 하나?",
  201. "조우\n시나리오와 관계없는 빌런 조직과 조우한다.",
  202. "평화\n별일 없었다.",
  203. ]
  204. ),
  205. }.freeze
  206. 1 register_prefix(
  207. 'BJ',
  208. 'DC[LSC]',
  209. TABLES.keys
  210. )
  211. end
  212. end
  213. end

lib/bcdice/game_system/BladeOfArcana.rb

97.65% lines covered

94.74% branches covered

85 relevant lines. 83 lines covered and 2 lines missed.
38 total branches, 36 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BladeOfArcana < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'BladeOfArcana'
  7. # ゲームシステム名
  8. 1 NAME = 'ブレイド・オブ・アルカナ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ふれいとおふあるかな'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ■行為判定 nA[m][Cx][Fy]
  14.  n:ダイス数  m:判定値(省略時はクリティカル値と同じ)
  15.  x:クリティカル値(省略時は1)  y:ファンブル値(省略時は20)
  16.  注)[m]、[Cx]、[Fy]は省略可能。
  17.   例)3A12C4F15→3個振り12以下で成功。C値4、F値は15。
  18.   例)3A12→3個振り12以下で成功。C値1、F値は20。
  19. ■各種表 (+:出目2~21に変更 -:出目0~19に変更)
  20. ●リインカーネイション
  21.  因縁表 CTR[+/-]  前世邂逅表 DJV[-]
  22.  悪徳シーン表 AKST[+/-]
  23. ●The 3rd(第三版)
  24.  因縁表 CT3[+/-]
  25.  注)[]内は省略可能。
  26.   例)CTR→因縁表(R版)を出目1~20でロールする。
  27.   例)CTR+→因縁表(R版)を出目2~21でロールする。
  28. INFO_MESSAGE_TEXT
  29. 1 register_prefix(
  30. '\d+A',
  31. 'CT3[\+\-]?',
  32. 'CTR[\+\-]?',
  33. 'DJV\-?',
  34. 'AKST[\+\-]?'
  35. )
  36. 1 def initialize(command)
  37. 34 super(command)
  38. 34 @sort_add_dice = true
  39. end
  40. 1 def eval_game_system_specific_command(command)
  41. 31 else: 1 case command.upcase
  42. when: 19 when /^(\d+)A(\d*)([CF]?)(\d*)([CF]?)(\d*)$/
  43. 19 counts = Regexp.last_match(1).to_i
  44. 19 judgment = Regexp.last_match(2).to_i
  45. 19 option1 = Regexp.last_match(3)
  46. 19 argument1 = Regexp.last_match(4)
  47. 19 option2 = Regexp.last_match(5)
  48. 19 argument2 = Regexp.last_match(6)
  49. 19 then: 7 else: 12 return nil if (option1.empty? != argument1.empty?) || (option2.empty? != argument2.empty?) || (!option2.empty? && (option1 == option2))
  50. 12 then: 6 if option1 == 'C'
  51. 6 critical = argument1.to_i
  52. 6 fumble = argument2.to_i
  53. else: 6 else
  54. 6 critical = argument2.to_i
  55. 6 fumble = argument1.to_i
  56. end
  57. 12 return rollAct(counts, judgment, critical, fumble)
  58. when: 3 when /^CT3([+-]?)$/
  59. 3 sign = Regexp.last_match(1)
  60. 3 title = '因縁表(The 3rd) 『BoA3』P292'
  61. 3 table = [
  62. "【他生】",
  63. "【師弟】",
  64. "【忘却】",
  65. "【兄姉】",
  66. "【貸し】",
  67. "【慕情】",
  68. "【主従】",
  69. "【強敵】",
  70. "【秘密】",
  71. "【恩人】",
  72. "【告発】",
  73. "【友人】",
  74. "【仇敵】",
  75. "【父母】",
  76. "【借り】",
  77. "【信頼】",
  78. "【幼子】",
  79. "【取引】",
  80. "【地縁】",
  81. "【同志】",
  82. "【不審】",
  83. "【自身】",
  84. ]
  85. 3 return tableText(title, table, sign)
  86. when: 3 when /^CTR([+-]?)$/
  87. 3 sign = Regexp.last_match(1)
  88. 3 title = '因縁表(リインカーネイション) 『BAR』P51、299'
  89. 3 table = [
  90. "【他生】",
  91. "【師弟】",
  92. "【忘却】",
  93. "【兄姉】",
  94. "【貸し】",
  95. "【憧憬】",
  96. "【主従】",
  97. "【強敵】",
  98. "【秘密】",
  99. "【恩人】",
  100. "【取引】",
  101. "【友人】",
  102. "【怨敵】",
  103. "【後援】",
  104. "【借り】",
  105. "【信頼】",
  106. "【弟妹】",
  107. "【商売】",
  108. "【奇縁】",
  109. "【同志】",
  110. "【有為】",
  111. "【自身】",
  112. ]
  113. 3 return tableText(title, table, sign)
  114. when: 2 when /^DJV(-?)$/
  115. 2 sign = Regexp.last_match(1)
  116. 2 title = '前世邂逅表(デジャブ) 『BAR』P235'
  117. 2 table = [
  118. "【鮮烈な風】\n風は懐かしい匂いを、香りを運んでくる。それは……。",
  119. "【薄暗い影】\nまるで時が止まってしまっているかのようだ。",
  120. "【操りの糸】\nそれはあなたを導く蜘蛛の糸。",
  121. "【天上の光】\n偉大なるものがもたらす、天上からの御しるし。",
  122. "【温もり】\n春のひなたのような温かさを感じる。",
  123. "【鋭いナイフ】\n鋭いナイフのような視線を感じる。これは……。",
  124. "【共鳴】\n同じ感覚を感じる、ふたりは通じ合っている。",
  125. "【城壁】\n厳しく高い城壁のように重く堅く厚い。",
  126. "【砕ける器】\n落ちれば砕ける。砕ければそれは器ではない。",
  127. "【陽炎】\n求めれば揺らいで消える。",
  128. "【終わりなき円環】\nそれはあなたを捉え巡る輪廻の輪。",
  129. "【天秤】\n揺れるバランス、揺れ続ける安定。",
  130. "【流れる水】\nひとつ所にとどまらず、姿を固めることはない",
  131. "【光る刃】\n鋭く光る刃のような、鋭いまなざし。",
  132. "【悪魔】\nあまりにも危険な魅力、それは悪魔的だった。",
  133. "【牙】\n獲物を引き裂く鋭く長い、牙。",
  134. "【輝く星】\n星は暗く小さい。だがそこに輝く。",
  135. "【冴え渡る月光】\n冷たさと安らかさが同居している。",
  136. "【照りつける太陽】\n暑い。",
  137. "【燃えさかる炎】\n炎はすべてを破壊し、すべてを滅ぼす。",
  138. "【世界】\nすべてはこの世界の中で起こり、終わる。",
  139. "【なし】",
  140. ]
  141. 2 return tableText(title, table, sign)
  142. when: 3 when /^AKST([+-]?)$/
  143. 3 sign = Regexp.last_match(1)
  144. 3 title = '悪徳シーン表 『GoV』P16、164'
  145. 3 table = [
  146. "▼ウェントス/止まない風\n【行動】殺戮者の狂気に当てられたのか、通り魔的殺人者が現れる。切り裂かれた人々の悲鳴が響き渡る。",
  147. "▼エフェクトス/原初の力\n【行動】殺戮者の配下が無法を働く。店先で金品を要求したり、暴力を振るったりしている。",
  148. "▼クレアータ/傀儡人形の王\n【行動】殺戮者の配下が人々の行動を監視している。違反した者には即座に罰が与えられる。",
  149. "▼マーテル/生ける神\n【行動】殺戮者の配下が人々に殺戮者への信仰を告白し、忠誠を宣誓するように強要している。",
  150. "▼コロナ/簒奪者\n【行動】嘆き悲しんでいる者がいる。殺戮者によって、財産、地位、家族あるいは、恋人を奪い取られたという。",
  151. "▼フィニス/永遠の人\n【行動】怪物が人々を虐殺している。この地には人間が多すぎるのだという。それが彼らの主の決定だ。",
  152. "▼エルス/無私なる愛\n【行動】殺戮者の配下が略奪を働いている。どうやら、殺戮者に献上するものを争っているようだ。",
  153. "▼アダマス/万物の保護者\n【行動】反逆者と名指しされる。人々は君たちに接触しようとしない。情報を集めるにも苦労しそうだ。",
  154. "▼アルドール/終わりなき戦い\n【行動】ならず者の集団が人々を襲っている。力を示さなければ切り捨てられるのは彼らなのだ。",
  155. "▼ファンタスマ/謀略の渦\n【行動】人々は君を見るなり逃げ出した。どうやら恐ろしい殺人者だと思われているようだ。",
  156. "▼アクシス/真理の探究者\n【行動】殺戮者の配下の手によって、人々が連れ去られている。誰ひとりもどってこない。",
  157. "▼レクス/捕縛者\n【行動】殺戮者への恐怖に駆られた人々はその命令にしたがって徒党を組み、PCたちを捜索している。",
  158. "▼アクア/澱んだ水\n【行動】人々は獣のように生きている。言葉は通じない。有効なのは力、暴力だけだ。",
  159. "▼グラディウス/暗き死の刃\n【行動】殺戮者とその配下によって虐殺が行なわれている。見渡す限り、死者ばかりだ。",
  160. "▼アングルス/純白の恐怖\n【行動】遊びとして人間狩りが行なわれている。人々は逃げ惑い、殺戮者は愉悦に笑う。",
  161. "▼ディアボルス/悪魔の囁き\n【行動】殺戮者は少年少女を召し上げている。召し上げられた者たちは音信不通となってしまう。",
  162. "▼フルキフェル/裏切り者\n【行動】人々は猜疑の目で君を見る。嘘を吐くのが普通の場所で真実を見いだせるだろうか。",
  163. "▼ステラ/破滅への愛\n【行動】街や村落が破壊されている。焼け野原の中、人々は力なくうずくまる。ここには絶望だけがあった。",
  164. "▼ルナ/奪う者\n【行動】君たちの目の前に略奪が繰り返される。略奪のために略奪を行なう殺戮者の配下たち。",
  165. "▼デクストラ/邪悪な技\n【行動】殺戮者による非道な人体実験が繰り返されている。そのための実験材料が集められている。",
  166. "▼イグニス/根源たる炎\n【行動】街や集落、あるいは店舗や住宅が焼き討ちに合う。人々は互いに陥れ、磔刑が行なわれている。",
  167. "▼オービス/闇の鎖\n【行動】世界の完全なる破滅、人類の絶滅、無作為で広範囲な虐殺が行なわれる。",
  168. ]
  169. 3 return tableText(title, table, sign)
  170. end
  171. 1 return nil
  172. end
  173. 1 def rollAct(counts, judgment = 0, critical = 0, fumble = 0)
  174. 12 then: 5 else: 7 if critical < 1
  175. 5 critical = 1
  176. end
  177. 12 then: 3 if judgment <= 0
  178. 3 else: 9 judgment = critical
  179. 9 then: 2 else: 7 elsif critical > judgment
  180. 2 critical = judgment
  181. end
  182. 12 then: 6 else: 6 if fumble <= 0
  183. 6 fumble = 20
  184. end
  185. 12 then: 1 else: 11 if counts <= 0
  186. 1 counts = 1
  187. 1 fumble -= 5
  188. end
  189. 12 then: 0 if fumble < 2
  190. else: 12 fumble = 2
  191. 12 then: 0 else: 12 elsif fumble > 20
  192. fumble = 20
  193. end
  194. 12 dice_list = @randomizer.roll_barabara(counts, 20).sort
  195. 12 value = dice_list.sum()
  196. 12 string = dice_list.join(",")
  197. 12 text = "(#{counts}A#{judgment}C#{critical}F#{fumble}) > #{string} > "
  198. 12 else: 4 then: 8 unless counts == 1
  199. 8 value = string.split(",").map(&:to_i).min
  200. 8 text += "#{value} > "
  201. end
  202. 12 then: 2 if value >= fumble
  203. 2 else: 10 text += 'ファンブル'
  204. 10 then: 1 elsif value <= critical
  205. 1 else: 9 text += 'クリティカル'
  206. 9 then: 5 elsif value > judgment
  207. 5 text += '失敗'
  208. else: 4 else
  209. 4 text += '成功'
  210. end
  211. 12 return text
  212. end
  213. 1 def tableText(title, table, sign = '')
  214. 11 number = @randomizer.roll_once(20)
  215. 11 index = number
  216. 11 then: 3 if sign == '+'
  217. 3 else: 8 index += 1
  218. 8 then: 4 else: 4 elsif sign == '-'
  219. 4 index -= 1
  220. end
  221. 11 text = "#{title} > #{index}"
  222. 11 else: 4 then: 7 unless sign.empty?
  223. 7 text += "[#{number}#{sign}1]"
  224. end
  225. 11 return text + ' > ' + table[index]
  226. end
  227. end
  228. end
  229. end

lib/bcdice/game_system/BlindMythos.rb

99.41% lines covered

97.1% branches covered

170 relevant lines. 169 lines covered and 1 lines missed.
69 total branches, 67 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BlindMythos < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'BlindMythos'
  7. # ゲームシステム名
  8. 1 NAME = 'ブラインド・ミトスRPG'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ふらいんとみとすRPG'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定:BMx@y>=z、BMSx@y>=z
  14.  x:スキルレベル
  15.   y:目標難易度(省略可。デフォルト4)
  16.   z:必要成功度
  17.  BMコマンドはダイスの振り足しを常に行い、
  18.  BMSは振り足しを自動では行いません。
  19. 例)BM>=1 BM@3>=1 BMS2>=1
  20. ・判定振り足し:ReRollx,x,x...@y>=z
  21.  x:振るダイスの個数
  22.   y:目標難易度(省略可。デフォルト4)
  23.   z:必要成功度
  24.  振り足しを自動で行わない場合(BMSコマンド)に使用します。
  25. ・LE:失う感情表
  26. ・感情後遺症表 ESx
  27.  ESH:喜、ESA:怒、ESS:哀、ESP:楽、ESL:愛、ESE:感
  28. ・DT:汚染チャート
  29. ・RPxyz:守護星表チェック
  30. xyz:守護星ナンバーを指定
  31. 例)RP123 RP258
  32. MESSAGETEXT
  33. 1 def eval_game_system_specific_command(command)
  34. 39 debug("eval_game_system_specific_command Begin")
  35. 39 result = judgeRoll(command)
  36. 39 else: 20 then: 19 return result unless result.nil?
  37. 20 isStop = true
  38. 20 text, = reRoll(command, isStop)
  39. 20 else: 17 then: 3 return text unless text.nil?
  40. 17 result = getRulingPlanetDiceCommandResult(command)
  41. 17 else: 14 then: 3 return result unless result.nil?
  42. 14 text = getDurtyTableCommandReuslt(command)
  43. 14 else: 7 then: 7 return text unless text.nil?
  44. 7 return roll_tables(command, TABLES)
  45. end
  46. 1 def judgeRoll(command)
  47. 39 else: 19 then: 20 return nil unless /^BM(S)?(\d*)(@(\d+))?>=(\d+)$/i =~ command
  48. 19 isStop = !Regexp.last_match(1).nil?
  49. 19 skillRank = Regexp.last_match(2).to_i
  50. 19 judgeNumberText = Regexp.last_match(3)
  51. 19 judgeNumber = (Regexp.last_match(4) || 4).to_i
  52. 19 targetNumber = (Regexp.last_match(5) || 1).to_i
  53. 19 message = ""
  54. 19 diceCount = skillRank + 2
  55. 19 isReRoll = false
  56. text, bitList, successList, countOneList, canReRoll =
  57. 19 getRollResult([diceCount], judgeNumberText, judgeNumber, targetNumber, isReRoll, isStop)
  58. 19 message += text
  59. 19 result = getTotalResult(bitList, successList, countOneList, targetNumber, isStop, canReRoll)
  60. 19 result.text = message + result.text
  61. 19 return result
  62. end
  63. 1 def reRoll(command, isStop)
  64. 26 debug("ReRoll Begin", command)
  65. 26 else: 9 then: 17 return nil unless /^ReRoll([\d,]+)(@(\d+))?>=(\d+)$/i =~ command
  66. 9 debug("ReRoll pass")
  67. 9 rerollCountsText = Regexp.last_match(1)
  68. 9 judgeNumberText = Regexp.last_match(2)
  69. 9 judgeNumber = (Regexp.last_match(3) || 4).to_i
  70. 9 targetNumber = Regexp.last_match(4).to_i
  71. 9 rerollCounts = rerollCountsText.split(/,/).map(&:to_i)
  72. 9 commandText = ""
  73. 9 rerollCounts.each do |diceCount|
  74. 14 else: 9 then: 5 commandText += "," unless commandText.empty?
  75. 14 commandText += "ReRoll#{diceCount}#{judgeNumberText}>=#{targetNumber}"
  76. end
  77. 9 debug("commandText", commandText)
  78. 9 message = ""
  79. 9 then: 3 else: 6 if rerollCounts.size > 1 && isStop
  80. 3 message += "(#{commandText})"
  81. end
  82. 9 message += "\n"
  83. 9 isReRoll = true
  84. text, _bitList, successList, countOneList, =
  85. 9 getRollResult(rerollCounts, judgeNumberText, judgeNumber, targetNumber, isReRoll, isStop)
  86. 9 message += text
  87. 9 return message, successList, countOneList, targetNumber
  88. end
  89. 1 def getRollResult(rerollCounts, judgeNumberText, judgeNumber, targetNumber, isReRoll, isStop)
  90. 28 bitList = []
  91. 28 successList = []
  92. 28 countOneList = []
  93. 28 rerollTargetList = []
  94. 28 message = ""
  95. 28 rerollCounts.each_with_index do |diceCount, index|
  96. 33 else: 28 then: 5 message += "\n" unless index == 0
  97. 33 commandName = "ReRoll#{diceCount}"
  98. 33 else: 14 then: 19 unless isReRoll
  99. 19 then: 9 if isStop
  100. 9 commandName = "BMS#{diceCount - 2}"
  101. else: 10 else
  102. 10 commandName = "BM#{diceCount - 2}"
  103. end
  104. end
  105. 33 commandText = "#{commandName}#{judgeNumberText}>=#{targetNumber}"
  106. 33 diceList = @randomizer.roll_barabara(diceCount, 6).sort
  107. 33 diceText = diceList.join(",")
  108. 33 then: 14 else: 19 message += " > " if isReRoll
  109. 33 message += "(#{commandText}) > #{diceCount}D6[#{diceText}] > "
  110. 33 success, countOne, resultText = getSuccessResultText(diceList, judgeNumber)
  111. 106 else: 14 then: 19 bitList += diceList.find_all { |i| i >= 4 } unless isReRoll
  112. 33 successList << success
  113. 33 countOneList << countOne
  114. 33 message += resultText
  115. 33 sameDiceList = getSameDieList(diceList)
  116. 33 then: 14 else: 19 next if sameDiceList.empty?
  117. 19 rerollText = ""
  118. 19 sameDiceList.each do |list|
  119. 25 else: 19 then: 6 rerollText += "," unless rerollText.empty?
  120. 25 rerollText += list.join('')
  121. end
  122. 19 rerollTargetList << sameDiceList.map(&:count).join(",")
  123. 19 message += "、リロール[#{rerollText}]"
  124. end
  125. 28 rerollCommand = ""
  126. 28 else: 10 then: 18 unless rerollTargetList.empty?
  127. 18 rerollCommand = "ReRoll#{rerollTargetList.join(',')}#{judgeNumberText}>=#{targetNumber}"
  128. 18 then: 12 else: 6 message += "\n > コマンド:#{rerollCommand}" if isStop
  129. end
  130. 28 canReRoll = !rerollCommand.empty?
  131. # ゲームシステムの識別子
  132. # ゲームシステム名
  133. # ゲームシステム名の読みがな
  134. # ダイスボットの使い方
  135. 28 then: 6 else: 22 if canReRoll && !isStop
  136. 6 text, successListTmp, countOneListTmp, = reRoll(rerollCommand, isStop)
  137. 6 message += text
  138. 6 successList += successListTmp
  139. 6 countOneList += countOneListTmp
  140. end
  141. 28 return message, bitList, successList, countOneList, canReRoll
  142. end
  143. 1 def getTotalResult(bitList, successList, countOneList, targetNumber, isStop, canReRoll)
  144. 27 success = successList.inject { |sum, i| sum + i }
  145. 27 countOne = countOneList.inject { |sum, i| sum + i }
  146. 19 result = ""
  147. 19 then: 5 else: 14 if successList.size > 1
  148. 5 result += "\n > 最終成功数:#{success}"
  149. end
  150. 19 then: 9 else: 10 if canReRoll && isStop
  151. 9 result += "\n"
  152. 9 then: 8 if success >= targetNumber
  153. 8 result += " > 現状で成功。コマンド実行で追加リロールも可能"
  154. 8 return Result.success(result)
  155. else: 1 else
  156. 1 result += " > 現状のままでは失敗"
  157. 1 then: 1 if countOne >= 1
  158. 1 result += "。汚染ポイント+#{countOne}"
  159. 1 return Result.fumble(result)
  160. else: 0 else
  161. return Result.failure(result)
  162. end
  163. end
  164. end
  165. 10 then: 7 if success >= targetNumber
  166. 7 result += " > 成功"
  167. 7 then: 6 if bitList.size >= 1
  168. 6 result += "、禁書ビット発生[#{bitList.join(',')}]"
  169. 6 return Result.critical(result)
  170. else: 1 else
  171. 1 return Result.success(result)
  172. end
  173. else: 3 else
  174. 3 result += " > 失敗"
  175. 3 then: 2 if countOne >= 1
  176. 2 result += "。汚染ポイント+#{countOne}"
  177. 2 return Result.fumble(result)
  178. else: 1 else
  179. 1 return Result.failure(result)
  180. end
  181. end
  182. end
  183. 1 def getSameDieList(diceList)
  184. 33 sameDiceList = []
  185. 33 diceList.uniq.each do |i|
  186. 69 then: 16 else: 53 next if i == 1
  187. 244 list = diceList.find_all { |dice| dice == i }
  188. 53 then: 28 else: 25 next if list.length <= 1
  189. 25 sameDiceList << list
  190. end
  191. 33 return sameDiceList
  192. end
  193. 1 def getSuccessResultText(diceList, judgeNumber)
  194. 33 success = 0
  195. 33 countOne = 0
  196. 33 diceList.each do |i|
  197. 111 then: 20 else: 91 countOne += 1 if i == 1
  198. 111 else: 65 then: 46 next unless i >= judgeNumber
  199. 65 success += 1
  200. end
  201. 33 result = "成功数:#{success}"
  202. 33 return success, countOne, result
  203. end
  204. 1 def getRulingPlanetDiceCommandResult(command)
  205. 17 m = /^RP(\d+)$/i.match(command)
  206. 17 else: 3 then: 14 return nil unless m
  207. 3 targetNumbers = m[1].each_char.map(&:to_i)
  208. 3 diceList = getRulingPlanetDice
  209. 8 condition = diceList.any? { |dice| targetNumbers.include?(dice) }
  210. 3 then: 2 else: 1 result = condition ? "発動" : "失敗"
  211. 3 text = "守護星表チェック(#{targetNumbers.join(',')}) > #{diceList.count}D10[#{diceList.join(',')}] > #{result}"
  212. 3 Result.new.tap do |r|
  213. 3 r.text = text
  214. 3 r.condition = condition
  215. end
  216. end
  217. 1 def getRulingPlanetDice
  218. 3 dice1, dice2 = @randomizer.roll_barabara(2, 10)
  219. 3 body: 2 while dice1 == dice2
  220. 2 dice2 = @randomizer.roll_once(10)
  221. end
  222. 3 then: 0 else: 3 dice1 = 0 if dice1 == 10
  223. 3 then: 2 else: 1 dice2 = 0 if dice2 == 10
  224. 3 return dice1, dice2
  225. end
  226. 1 def getDurtyTableCommandReuslt(command)
  227. 14 else: 7 then: 7 return nil unless /^DT$/i =~ command
  228. 7 table = <<~__TABLE_END__
  229. 汚染チャートを2回振り、その効果を適用する(1・2-2,5・6-12 なら振り直す)
  230. PC全員の「トラウマ」「喪失」すべてに2ダメージ
  231. PC全員の「喪失」2つに4ダメージ
  232. PC全員の「トラウマ」すべてに2ダメージ。その後さらに汚染が2増える
  233. PC全員、1つの【記憶】の両方の値が0になる。このときアクロバットダイス獲得不可
  234. PC全員の「喪失」1つに4ダメージ。このときアクロバットダイス獲得不可
  235. PC全員の「トラウマ」すべてに1ダメージ。その後さらに汚染が3増える
  236. PC全員の「トラウマ」すべてに1ダメージ。その後アクロバットダイスをPC人数分失う
  237. PC全員の「喪失」すべてに2ダメージ。禁書ビットをすべて失う
  238. PC全員の「トラウマ」2つに3ダメージ。その後さらに汚染が1増える
  239. PC全員の「トラウマ」「喪失」すべてに1ダメージ
  240. PC全員の「喪失」1つに4ダメージ。禁書ビットをすべて失う
  241. PC全員の「トラウマ」すべてに2ダメージ
  242. PC全員の1つの【記憶】の「トラウマ」「喪失」それぞれに3ダメージ
  243. PC全員の「喪失」すべてに1ダメージ
  244. PC全員の「トラウマ」3つに2ダメージ
  245. PC全員の「トラウマ」と「喪失」それぞれ1つに3ダメージ
  246. PC全員の「喪失」3つに2ダメージ
  247. PC全員のすべての「トラウマ」に1 ダメージ
  248. PC全員のひとつの【記憶】の「トラウマ」「喪失」それぞれに3ダメージ
  249. PC全員の「喪失」すべてに2ダメージ
  250. PC全員の「トラウマ」ひとつに4ダメージ。禁書ビットをすべて失う
  251. PC全員の「トラウマ」「喪失」すべてに1ダメージ
  252. PC全員の「喪失」2つに3ダメージ。その後さらに汚染が1増える
  253. PC全員の「トラウマ」すべてに2ダメージ。禁書ビットをすべて失う
  254. PC全員の「喪失」すべてに1ダメージ。その後アクロバットダイスをPC人数分失う
  255. PC全員の「喪失」すべてに1ダメージ。その後さらに汚染が3増える
  256. PC全員の「トラウマ」1つに4ダメージ。このときアクロバットダイス獲得不可
  257. PC全員、1つの【記憶】の両方の値が0になる。このときアクロバットダイス獲得不可
  258. PC全員の「喪失」すべてに2ダメージ。その後さらに汚染が2増える
  259. PC全員の「トラウマ」2つに4ダメージ
  260. PC全員の「トラウマ」「喪失」すべてに2ダメージ
  261. 汚染チャートを2回振り、その効果を適用する(1・2-2,5・6-12 なら振り直す)
  262. __TABLE_END__
  263. 7 table = table.split("\n")
  264. 7 dice1 = @randomizer.roll_once(6)
  265. 7 dice2 = @randomizer.roll_sum(2, 6)
  266. 7 index = (dice2 - 2) * 3 + (dice1 / 2.0).ceil - 1
  267. 7 return "汚染チャート(#{dice1},#{dice2}) > #{table[index]}"
  268. end
  269. TABLES = {
  270. 1 "LE" => DiceTable::Table.new(
  271. "失う感情表",
  272. "1D6",
  273. [
  274. "喜:喜びは消えた。嬉しい気持ちとは、なんだっただろう。",
  275. "怒:激情は失われ、憎しみもどこかへと消える。",
  276. "哀:どんなに辛くても、悲しさを感じない。どうやら涙も涸れたらしい。",
  277. "楽:もはや楽しいことなどない。希望を抱くだけ無駄なのだ。",
  278. "愛:愛など幻想……無力で儚い、役に立たない世迷い言だ。",
  279. "感:なにを見ても、感動はない。心は凍てついている。"
  280. ]
  281. ),
  282. "ESH" => DiceTable::Table.new(
  283. "「喜」の感情後遺症表",
  284. "2D6",
  285. [
  286. "日々喜びを求めてしまう。",
  287. "日々喜びを求めてしまう。",
  288. "嬉しい時間が長続きしない。",
  289. "素直に喜びを共有できないことがある。",
  290. "小さなことで大きく喜びを感じる。",
  291. "小さなことで大きく喜びを感じる。",
  292. "影響なし。",
  293. "影響なし。",
  294. "「喜」の後遺症をひとつ消してもよい。",
  295. "「喜」の後遺症をひとつ消してもよい。",
  296. "「喜」の後遺症をひとつ消してもよい。"
  297. ]
  298. ),
  299. "ESA" => DiceTable::Table.new(
  300. "「怒」の感情後遺症表",
  301. "2D6",
  302. [
  303. "始終不機嫌になる。",
  304. "始終不機嫌になる。",
  305. "一度怒ると、なかなか収まらない。",
  306. "怒りっぽくなる",
  307. "怒りかたが激しくなる。",
  308. "怒りかたが激しくなる。",
  309. "影響なし。",
  310. "影響なし。",
  311. "「怒」の後遺症をひとつ消してもよい。",
  312. "「怒」の後遺症をひとつ消してもよい。",
  313. "「怒」の後遺症をひとつ消してもよい。"
  314. ]
  315. ),
  316. "ESS" => DiceTable::Table.new(
  317. "「哀」の感情後遺症表",
  318. "2D6",
  319. [
  320. "一度涙が出るとなかなか止まらない。",
  321. "一度涙が出るとなかなか止まらない。",
  322. "夜、哀しいことを思い出して目が覚める。",
  323. "不意に哀しい気持ちになる。",
  324. "涙もろくなる。",
  325. "涙もろくなる。",
  326. "影響なし。",
  327. "影響なし。",
  328. "「哀」の後遺症をひとつ消してもよい。",
  329. "「哀」の後遺症をひとつ消してもよい。",
  330. "「哀」の後遺症をひとつ消してもよい。"
  331. ]
  332. ),
  333. "ESP" => DiceTable::Table.new(
  334. "「楽」の感情後遺症表",
  335. "2D6",
  336. [
  337. "突然陽気になったり、不意に笑い出してしまう。",
  338. "突然陽気になったり、不意に笑い出してしまう。",
  339. "周りが楽しくなさそうだと不安になる。",
  340. "楽しいことがないと落ち着かない。",
  341. "些細なことでも笑ってしまう。",
  342. "些細なことでも笑ってしまう。",
  343. "影響なし。",
  344. "影響なし。",
  345. "「楽」の後遺症をひとつ消してもよい。",
  346. "「楽」の後遺症をひとつ消してもよい。",
  347. "「楽」の後遺症をひとつ消してもよい。"
  348. ]
  349. ),
  350. "ESL" => DiceTable::Table.new(
  351. "「愛」の感情後遺症表",
  352. "2D6",
  353. [
  354. "少しでも気になる相手に愛を求めてしまう。",
  355. "少しでも気になる相手に愛を求めてしまう。",
  356. "愛する相手(恋人・家族・ペット・空想)から離れたくない。",
  357. "誰彼構わず優しくしてしまう。",
  358. "ひとりでいると不安を感じる。",
  359. "ひとりでいると不安を感じる。",
  360. "影響なし。",
  361. "影響なし。",
  362. "「愛」の後遺症をひとつ消してもよい。",
  363. "「愛」の後遺症をひとつ消してもよい。",
  364. "「愛」の後遺症をひとつ消してもよい。"
  365. ]
  366. ),
  367. "ESE" => DiceTable::Table.new(
  368. "「感」の感情後遺症表",
  369. "2D6",
  370. [
  371. "感動を共有できない相手を不信に思ってしまう。",
  372. "感動を共有できない相手を不信に思ってしまう。",
  373. "嬉しくても哀しくてもすぐに涙が出る。",
  374. "リアクションがオーバーになる。",
  375. "ちょっとしたことで感動する。",
  376. "ちょっとしたことで感動する。",
  377. "影響なし。",
  378. "影響なし。",
  379. "「感」の後遺症をひとつ消してもよい。",
  380. "「感」の後遺症をひとつ消してもよい。",
  381. "「感」の後遺症をひとつ消してもよい。"
  382. ]
  383. ),
  384. }.freeze
  385. 1 register_prefix('BM', 'ReRoll', 'RP', 'DT', TABLES.keys)
  386. end
  387. end
  388. end

lib/bcdice/game_system/BloodCrusade.rb

100.0% lines covered

100.0% branches covered

27 relevant lines. 27 lines covered and 0 lines missed.
8 total branches, 8 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BloodCrusade < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'BloodCrusade'
  7. # ゲームシステム名
  8. 1 NAME = 'ブラッド・クルセイド'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ふらつとくるせいと'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・各種表
  14.  ・関係属性表 RT
  15.  ・シーン表 ST
  16.  ・先制判定指定特技表 IST
  17.  ・身体部位決定表   BRT
  18.  ・自信幸福表     CHT
  19.  ・地位幸福表     SHT
  20.  ・日常幸福表     DHT
  21.  ・人脈幸福表     LHT
  22.  ・退路幸福表     EHT
  23.  ・ランダム全特技表  AST
  24.  ・軽度狂気表     MIT
  25.  ・重度狂気表     SIT
  26.  ・戦場シーン表    BDST
  27.  ・夢シーン表     DMST
  28.  ・田舎シーン表    CYST
  29.  ・学校シーン表    SLST
  30.  ・館シーン表     MNST
  31.  ・時間経過表(10代~60代、半吸血鬼)TD1T~TD6T、TDHT
  32. ・D66ダイスあり
  33. INFO_MESSAGE_TEXT
  34. 1 def initialize(command)
  35. 48 super(command)
  36. 48 @sort_add_dice = true
  37. 48 @d66_sort_type = D66SortType::ASC
  38. 48 @round_type = RoundType::CEIL # 端数切り上げに設定
  39. end
  40. 1 def result_2d6(total, dice_total, _dice_list, cmp_op, target)
  41. 5 then: 1 else: 4 return nil if target == '?' || cmp_op != :>=
  42. 4 then: 1 if dice_total <= 2
  43. 1 else: 3 Result.fumble("ファンブル(【モラル】-3。追跡フェイズなら吸血シーンを追加。戦闘フェイズなら吸血鬼は追加行動を一回得る)")
  44. 3 then: 1 elsif dice_total >= 12
  45. 1 else: 2 Result.critical("スペシャル(【モラル】+3。追跡フェイズならあなたに関係を持つPCの【モラル】+2。攻撃判定ならダメージ+1D6)")
  46. 2 then: 1 elsif total >= target
  47. 1 Result.success("成功")
  48. else: 1 else
  49. 1 Result.failure("失敗")
  50. end
  51. end
  52. 1 def eval_game_system_specific_command(command)
  53. 43 roll_tables(command, TABLES) || RTT.roll_command(randomizer, command)
  54. end
  55. 1 RTT = DiceTable::SaiFicSkillTable.new(
  56. [["社会", ["怯える", "脅す", "考えない", "自信", "黙る", "伝える", "だます", "地位", "笑う", "話す", "怒る"]],
  57. ["頭部", ["聴く", "感覚器", "見る", "反応", "考える", "脳", "閃く", "予感", "叫ぶ", "口", "噛む"]],
  58. ["腕部", ["締める", "殴る", "斬る", "利き腕", "撃つ", "操作", "刺す", "逆腕", "振る", "掴む", "投げる"]],
  59. ["胴部", ["塞ぐ", "呼吸器", "止める", "受ける", "測る", "心臓", "逸らす", "かわす", "耐える", "消化器", "落ちる"]],
  60. ["脚部", ["走る", "迫る", "蹴る", "利き脚", "跳ぶ", "仕掛ける", "踏む", "逆脚", "這う", "伏せる", "歩く"]],
  61. ["環境", ["休む", "日常", "隠れる", "待つ", "現れる", "人脈", "捕らえる", "開ける", "逃げる", "退路", "休まない"]],],
  62. rtt: 'AST',
  63. rtt_format: "ランダム全特技表(%<category_dice>d) > %<category_name>s(%<row_dice>d) > %<skill_name>s"
  64. )
  65. TABLES_WITH_BLOOD_MOON = {
  66. 1 "IST" => DiceTable::Table.new(
  67. "先制判定指定特技表",
  68. "1D6",
  69. [
  70. "《自信/社会5》",
  71. "《地位/社会9》",
  72. "《日常/環境3》",
  73. "《人脈/環境7》",
  74. "《退路/環境11》",
  75. "《心臓/胴部7》"
  76. ]
  77. ),
  78. "BRT" => DiceTable::Table.new(
  79. "身体部位決定表",
  80. "2D6",
  81. [
  82. "《脳》",
  83. "《利き腕》",
  84. "《利き脚》",
  85. "《消化器》",
  86. "《感覚器》",
  87. "《攻撃したキャラクターの任意》",
  88. "《口》",
  89. "《呼吸器》",
  90. "《逆脚》",
  91. "《逆腕》",
  92. "《心臓》"
  93. ]
  94. ),
  95. }.freeze
  96. TABLES = {
  97. 1 "RT" => DiceTable::Table.new(
  98. "関係属性表",
  99. "1D6",
  100. [
  101. "共感/不信",
  102. "友情/忌避",
  103. "愛情/嫌悪",
  104. "忠義/侮蔑",
  105. "憧憬/引け目",
  106. "保護欲/殺意"
  107. ]
  108. ),
  109. "CHT" => DiceTable::Table.new(
  110. "自信幸福表",
  111. "1D6",
  112. [
  113. "【戦闘能力】あなたは吸血鬼狩人としての自分の戦闘能力に自信を持っています。たとえ負けようとも、それは運か相手か仲間が悪かったので、あなたの戦闘能力が低いわけではありません。",
  114. "【美貌】あなたは自分が美しいことを知っています。他人もあなたを美しいと思っているはず。鏡を見るたびに、あなたは自分の美しさに惚れ惚れしてしまいます。",
  115. "【血筋】あなたは名家の血を引く者です。祖先の栄光を背負い、家門の名誉を更に増すために、偉業をなす運命にあります。または、普通にいい家族に恵まれているのかもしれません。",
  116. "【趣味の技量】あなたは趣味の分野では第一人者です。必ずしも名前が知れ渡っているわけではありませんが、どんな相手にも負けない自信があります。どんな趣味かは自由です。",
  117. "【仕事の技量】職場で最も有能なもの、それがあなたです。誰もあなたの仕事の量とクオリティを超えられません。どんな仕事をしているかは自由に決めて構いません。",
  118. "【長生き】あなたは吸血鬼狩人としてかなりの年月を過ごしてきたが、まだ死んでいません。これは誇るべきことです。そこらの若造には、まだまだ負けていません。"
  119. ]
  120. ),
  121. "SHT" => DiceTable::Table.new(
  122. "地位幸福表",
  123. "1D6",
  124. [
  125. "【役職】あなたは職場、あるいは吸血鬼狩人の組織のなかで高い階級についています。そのため、下にいるものには命令でき、相応の敬意を払われます。",
  126. "【英雄】あなたはかつて偉業を成し遂げたことがあり、誰でもそれを知っています。少々くすぐったい気もしますが、英雄として扱われるのは悪くありません。",
  127. "【お金持ち】あなたには財産があります。それも生半可な財産ではなく、人が敬意を払うだけの財産です。あなたはお金に困ることはなく、その幸せを知っています",
  128. "【特権階級】あなたは国が定める特権階級の一員です。王族や貴族をイメージするとわかりやすいでしょう。あなたは、どこに行っても、それ相応の扱いを受けることになります。",
  129. "【人格者】誰もが認める人格者としての評判を持っているため、あなたのところには悩みを抱えた人々が引きも切らずに押しかけてきます。大変ですが、ちょっと楽しい",
  130. "【リーダー】あなたは所属している何らかの組織を率いる立場にあります。会社の社長や、部活動の部長などです。あなたは求められてその地位にあります"
  131. ]
  132. ),
  133. "DHT" => DiceTable::Table.new(
  134. "日常幸福表",
  135. "1D6",
  136. [
  137. "【家】あなたの家はとても快適な空間です。コストと時間をかけて作り上げられた、あなたが居住するための空間。それはあなたの幸せの源なのです。",
  138. "【職場】あなたは仕事が楽しくて仕方ありません。意義ある仕事で払いも悪くなく、チームの仲間はみんないい奴ばかりです。残業は……ちょっとあるかもしれません。",
  139. "【行きつけの店】あなたには休みの日や職場帰りに立ち寄る行きつけの店があり、そこにいる時間は安らぎを感じることができます。店員とも顔見知りです。",
  140. "【ベッド】あなたは動物を飼っています。よく懐いた可愛い、またはかっこいい動物です。一緒に過ごす時間はあなたに幸せを感じさせてくれます",
  141. "【親しい隣人】おとなりさんやお向かいさん。よくお土産を渡したり、小さな子供を預かったりするような仲です。風邪を引いたときには、家事を手伝ってくれることも。",
  142. "【思い出】あなたは昔の思い出を心の支えにしています。何らかの幸せな記憶……それがあれば、この先にどんなつらいことが待っていても大丈夫でしょう。"
  143. ]
  144. ),
  145. "LHT" => DiceTable::Table.new(
  146. "人脈幸福表",
  147. "1D6",
  148. [
  149. "【理解ある家族】あなたの家族は、あなたが吸血鬼狩人であることを知ったうえで協力してくれます。これがどれほど稀なことかは、仲間に聞けば分かるでしょう。",
  150. "【有能な友人】あなたの友人は、吸血鬼の存在とあなたの本当の仕事を知っています。そして、直接戦うだけの技量はないものの、あなたの探索をサポートしてくれます。",
  151. "【愛する恋人】あなたには愛する人がいます。見つめあうだけで、あなたの心は舞い上がり……帰ってきません。この恋人を失うなんて、考えるだけでも恐ろしいことです。",
  152. "【同志の権力者】あなたには吸血鬼の存在を知りながら、奴らに屈していない権力者との繋がりがあります。様々な違法行為をはたらく際に、役に立つでしょう。",
  153. "【得がたい師匠】あなたは使う武器を学んだ師匠がいて、それを通して兄弟弟子とも繋がりがあります。過酷な訓練を経て、彼らとあなたには強い絆ができています。",
  154. "【可愛い子供】あなたには子供がいます。聡明で魅力的、しかも健康な……将来を嘱望される子供です。子供が掴む幸せな未来を思う時、あなたの顔には笑みが広がります。"
  155. ]
  156. ),
  157. "EHT" => DiceTable::Table.new(
  158. "退路幸福表",
  159. "1D6",
  160. [
  161. "【故郷の町】あなたは生まれ育った街を離れて吸血鬼狩人として活動しています。いつの日かあの町へ帰る……その思いがあなたを戦いのなかで支えています。",
  162. "【待っている人】あなたが吸血鬼狩人をやめて、普通の暮らしに戻ることを待ちわびている人がいます。そして、あなたはその思いに応えたいと思っています。",
  163. "【就職先】あなたは吸血鬼狩りの報酬がなくなっても、すぐに入ることができる就職先があるので安心です。有能なのか過疎地域なのかは分かりませんが。",
  164. "【配偶者】あなたは吸血鬼狩人をやめたあとに家庭に入ろうと考えています。暮らしの設計はすでに済み、あとは実行するだけなのですが、なかなかそうはいきません。",
  165. "【大志】あなたが吸血鬼狩人として活動しているのは、やむにやまれぬ事情があるからです。あなたには「本当にやりたかったこと」があり、いつかその夢をかなえる気でいます。",
  166. "【空想の王国】あなたには辛いことがあると白昼夢にふける、あるいは物語に没入する癖があり、そのときには非常に幸せな気分になることができます。"
  167. ]
  168. ),
  169. "BDST" => DiceTable::Table.new(
  170. "戦場シーン表",
  171. "2D6",
  172. [
  173. "塹壕。迫撃砲が唸りを上げ、兵士たちの悲鳴が響き渡る。",
  174. "港の堤防。遠ざかっていく貨物船と、ゆっくりと揺れる鉛色の水面。",
  175. "一面の草に覆われた野原。膝から下は見えない。",
  176. "ドーム競技場。中のフィールドよりも外の通路が使われることが多い。",
  177. "建物と建物の間に、いつの間にかできた空き地。入る道は狭い。",
  178. "採石場。背景を爆破するのに向いた場所だ。",
  179. "工場。用途の分からない巨大機械が放置され、雰囲気を盛り上げる。",
  180. "暗いトンネル。停められた車のヘッドライトだけが頼りだ。",
  181. "競馬場。人のいない観客席を広告板が見下ろしている。",
  182. "河川敷。土手の補強用ブロックの規則的な並びが目眩を引き起こす。",
  183. "司令室。壁の巨大スクリーンでは、何かのカウントダウンが進行中。"
  184. ]
  185. ),
  186. "CYST" => DiceTable::Table.new(
  187. "田舎シーン表",
  188. "2D6",
  189. [
  190. "誰かの家。庭付き二階建て。部屋は余っている。",
  191. "山。周囲は木に囲まれ、その向こうの景色は全く見えない。",
  192. "さびれたバス停。時刻表は錆に覆われていて読むのが難しい。",
  193. "国道沿いのファミレス。巨大な駐車場にトラックが並ぶ。",
  194. "大型量販店。服や靴、電化製品などの大きな店。",
  195. "あぜ道。周りには季節によって違う姿を見せる水田が広がる。",
  196. "大型ショッピングモール。何でも揃う。",
  197. "コンビニ。11時で閉まるので夜は開いていないこともある。",
  198. "野菜の無人販売所。木の棚に人参やジャガイモが置いてある。",
  199. "廃屋。近所の学生がよく忍び込んで悪さをしているとか。",
  200. "駅。ホームには屋根がなく、周りには山と森が広がっている。"
  201. ]
  202. ),
  203. "DMST" => DiceTable::Table.new(
  204. "夢シーン表",
  205. "2D6",
  206. [
  207. "愛しい人を抱きしめていると、いつのまにか別人に変わっていて驚く。",
  208. "もらった種を鉢に植えて待っていると、人が生えてきた。",
  209. "ひたすら落下し続けている。一緒に堕ちている人が何か叫んでいる。",
  210. "誰かをひどく殴りつけている。一発ごとに周りの観客から喝采が上がる。",
  211. "知らない人ばかりのパーティのなか、必死に知り合いを探している。",
  212. "何かに追いかけられて暗い道を走っている。そして追いつかれた。",
  213. "列車に乗って、通り過ぎていく景色を見ている。向かいの客席に誰かがいる。",
  214. "朝起きて冷蔵庫を開けにいくと、ありえない人物が朝食を作っていた。",
  215. "なぜか分からないが捕まって留置された。入れられた房には意外な人が。",
  216. "道端にいた散歩の犬が「これは夢だ」と事情を語り始めた。",
  217. "みんな死んでしまった。墓の前で座っていると、近づいてくる人影がある。"
  218. ]
  219. ),
  220. "MNST" => DiceTable::Table.new(
  221. "館シーン表",
  222. "2D6",
  223. [
  224. "地下牢。朽ち果てた骸の手首には鉄枷がはまったままだ。",
  225. "礼拝堂。何千本もの蝋燭が祭壇を照らす。",
  226. "厨房。得体の知れない鍋の中で何かが煮えたぎっている。",
  227. "客間。天蓋付きの寝台は分厚く暖かそうだ。",
  228. "中庭。ガゼボが配置されているが斬りかかってはいけない。",
  229. "天井の高い廊下。あちこちに風景画が飾られている。",
  230. "植木の迷路。動物型の植木が沈黙の咆哮をあげている。",
  231. "玄関ホール。もちろん二階まで吹き抜けで階段がある。",
  232. "食堂。果てしなく長いテーブルに椅子がセットされている。",
  233. "時計塔。巨大な歯車とシャフトの組み合わせが回る。",
  234. "領主の部屋。重厚なデスクと背後の本棚が威圧的だ。"
  235. ]
  236. ),
  237. "SLST" => DiceTable::Table.new(
  238. "学校シーン表",
  239. "2D6",
  240. [
  241. "廊下。消防ホースの箱がやたらと赤く目立つ",
  242. "運動場。石灰と混ざり合った白っぽい砂が積もっている。",
  243. "保健室。白いカーテンが揺れ、同じく白いベッドで影がおどる。",
  244. "講堂。ワックスのかかった床が、靴とこすれて甲高い音で鳴る。",
  245. "人でいっぱいの教室。みな座ってはいるがやかましい。",
  246. "誰もいない教室。時計の音がやけに大きく響く。",
  247. "昇降口。いくつも並んだ大きな下駄箱に名前が書かれている。",
  248. "音楽室。作曲家の肖像画がピアノを見下ろしている。",
  249. "理科室。薬品と埃の臭いが鼻をつく。",
  250. "工作室。机の大きな傷には木くずが詰まっている。",
  251. "開かずの教室。ここは真っ暗だ……出口も入り口もない。"
  252. ]
  253. ),
  254. "TD1T" => DiceTable::Table.new(
  255. "時間経過表十代",
  256. "1D6",
  257. [
  258. "自分探しの旅に出た。旅先で見つけた新しい自分は、なかなか好きになれるやつだった。\n狩人は主武装のうち一つを変更してもかまわない。変更したらキャラクターの再構築を行う。",
  259. "吸血鬼狩りを通して、仲間との絆が深まる。\n仲間の狩人から一人を目標として選び、その狩人に対する関係【震度】を2増加させる。\nその状態でセッションを開始する。",
  260. "自分の将来に不安を覚え、吸血鬼狩り以外のことにチャレンジしてみるものの、どれも中途半端でうまくいかない。\n狩人は「動転」の変調を発動した状態でセッションを開始する。",
  261. "最近イヤなことがあって、相当不機嫌な状態になっている。\n【モラル】の現在値を0にし、その状態でセッションを開始する。",
  262. "新しい友達が出来る。\n狩人と同じ年齢の協力者を、狩人のプレイヤーが作成する。レベルは1とすること。\nこの協力者はセッションに登場し、獲得すれば使用できる。",
  263. "ちょっと見ないうちに協力者が成長する。\n協力者を獲得している場合、その中から一人を選ぶ。\nその協力者のレベルが1上昇する。\n協力者を獲得していない場合、効果はない。"
  264. ]
  265. ),
  266. "TD2T" => DiceTable::Table.new(
  267. "時間経過表二十代",
  268. "1D6",
  269. [
  270. "表の仕事や学業で大抜擢され、若き天才として大いに名をはせる。\n【モラル】が3増加し、その状態でセッションを開始する。",
  271. "人生の新たな楽しみを発見する。\n【幸福】を一つ新たに設定し、獲得できる。\n【人間力】が足りない場合は、入れ替えるか無視すること。",
  272. "恋人との関係がシリアスなトラブルに変化する。\nまだ解決してはいないが、かなりのストレスだ。\n【感情】が3増加した状態でセッションを開始する。",
  273. "休暇中に無茶をして大怪我を負ってしまう。\n吸血鬼狩りはタイミングが命なので、怪我をおして参加することになる。\n狩人は「重症」の変調を発動した状態でセッションを開始する。",
  274. "新しい友達が出来た。\n狩人と五歳差までで任意の年齢の協力者を、狩人のプレイヤーが作成する。\nレベルは1とすること。この協力者はセッションに登場し、獲得すれば使用できる。",
  275. "協力者を獲得している場合、そのうち一人に絡んだイベントが発生していた。\n「転職」「結婚」「挫折」「失恋」「出産」「その他」などから一つを任意に選び、その協力者のレベルを1上げる。\n協力者を獲得していない場合、狩人のイベントとなり効果はない。"
  276. ]
  277. ),
  278. "TD3T" => DiceTable::Table.new(
  279. "時間経過表三十代",
  280. "1D6",
  281. [
  282. "ある種の慎重さを身につけ、常に狩りの準備を怠らないようになる。\n再殺武装から一つを選び、それをすでに獲得した状態でセッションを開始する。",
  283. "拠点の運営に協力し、管理を最適化して簡単に利用できるようにした。\n狩人側の拠点を一つ選び、その必要レベルを1減少させる。\nただし1未満にはならない。",
  284. "だんだんと責任のある立場になるにつれ、それに縛られているような感慨を覚えるようになる。\n「捕縛」の変調を発動した状態でセッションを開始する。",
  285. "狩人の噂を聞きつけた協力者が現れ、知己を得る。\n狩人と十歳差までで任意の年齢の協力者を、狩人のプレイヤーが作成する。\nレベルは1とすること。\nこの協力者はセッションに登場し、獲得すれば使用できる。",
  286. "軽い生活習慣病を発症する。特に狩りに影響はしない。",
  287. "協力者を獲得している場合、そのうち一人に絡んだイベントが発生していた。\n「転職」「結婚」「挫折」「失恋」「出産」「その他」などから一つを任意に選び、その協力者のレベルを1上げる。\n協力者を獲得していない場合、狩人のイベントとなり効果はない。"
  288. ]
  289. ),
  290. "TD4T" => DiceTable::Table.new(
  291. "時間経過表四十代",
  292. "1D6",
  293. [
  294. "だんだんと物事に動じず、迷わなくなってきた自分に気づく。\nこのセッションの遭遇シーンでは感情属性を任意に設定できる。",
  295. "重厚さを増す大人のオーラによって、他の狩人からの尊敬を勝ち取ることに成功する。\n仲間の狩人から目標を一人選び、目標から狩人への関係【深度】を1増加する。",
  296. "後進の育成に熱心になる。\nこのセッションの間、自分の追跡シーンに自分より若い味方キャラクターが登場している場合、判定にプラス1の修正がつく。\nこの修正は累積しない。",
  297. "大病発覚。\n狩人に後継者がいる場合、結果フェイズで狩人は死亡する。\n後継者がいない場合、またはセッション中に決別したり裏切られた場合には、奇跡的に回復する。",
  298. "幅広い人脈の中から吸血鬼の実在に耐えられる人物を見つけ出す。\n狩人と二十歳差までで任意の年齢の協力者を、狩人のプレイヤーが作成する。\nレベル1とすること。\nこの協力者はセッションに登場し、獲得すれば使用できる。",
  299. "協力者を獲得している場合、そのうち一人に絡んだイベントが発生していた。\n「転職」「結婚」「挫折」「失恋」「出産」「その他」などから一つを任意に選び、その協力者のレベルを1上げる。\n協力者を獲得していない場合、狩人のイベントとなり効果はない。"
  300. ]
  301. ),
  302. "TD5T" => DiceTable::Table.new(
  303. "時間経過表五十代",
  304. "1D6",
  305. [
  306. "長年の経験によって【人間力】がこのセッションの間だけ1増加し、【幸福】も一つ獲得する。\nこの効果は累積せず、すでに【人間力】が5の場合は効果なし。",
  307. "武器の扱いにトリックを付け加える。\n【ダメージ修正】がこのセッションの間だけ1増加する。この効果は累積しない。",
  308. "長年酷使されてきた体が、そろそろ狩りについていけなくなる。\n「捕縛」の変調を発動した状態でセッションを開始する。",
  309. "大病発覚。狩人に後継者がいる場合、結果フェイズで狩人は死亡する。\n後継者がいない場合、またはセッション中に決別したり裏切られた場合には、奇跡的に回復する。",
  310. "協力者を獲得している場合、そのうち一人が爆発的な成長を見せる。\nその協力者のレベルを2上げる。協力者を獲得していない場合、効果はなし。",
  311. "協力者を獲得している場合、そのうち一人に絡んだイベントが発生していた。\n「転職」「結婚」「挫折」「失恋」「出産」「その他」などから一つを任意に選び、その協力者のレベルを1上げる。\n協力者を獲得していない場合、狩人のイベントとなり効果はない。"
  312. ]
  313. ),
  314. "TD6T" => DiceTable::Table.new(
  315. "時間経過表六十代",
  316. "1D6",
  317. [
  318. "偉大な狩人の風格を漂わせることに成功。\n狩人のことを慕い、狩人に対して【深度】5の関係があるレベル7の協力者を獲得する。\n望むなら即座に後継者にしてもよい。",
  319. "吸血鬼の永遠の命に対する憧れが膨れあがってくる。\nセッションの間、「誘惑」に対する抵抗判定にマイナス2の修正がつく。\nこの効果は累積しない。",
  320. "隠退生活に思いをはせ始める。\nもはや狩りにあまり積極的にはなれず、【モラル】の現在値を0にし、その状態でセッションを開始する。",
  321. "大病発覚。\n狩人に後継者がいる場合、結果フェイズで狩人は死亡する。\n後継者がいない場合、またはセッション中に決別したり裏切られた場合には、奇跡的に回復する。",
  322. "ふと死期を悟る。次の狩りが最後になるだろう。\nセッションの間、暴走のたびに【激情】を二つ獲得できる。\n結果フェイズで狩人は死亡する。",
  323. "協力者を獲得している場合、その指導に一年をかける。\n協力者のなかから一人を選び、その協力者のレベルを2上げる。\n協力者を獲得していない場合、のんびりした一年だった。"
  324. ]
  325. ),
  326. "TDHT" => DiceTable::Table.new(
  327. "時間経過表半吸血鬼",
  328. "1D6",
  329. [
  330. "じっくりと時間をかけて、敵吸血鬼の個性を研究する。\nこのセッションの間、吸血鬼を目標とした「前哨戦」の判定にプラス1の修正がつく。\nこの効果は累積しない。",
  331. "自分の血の力について考慮を深め、より自由に使いこなせるようになる。\n修得している血戒グループのアビリティから一つを選び、その名前に「+」をつけること。\nそのアビリティの反動はやはり二倍だが、【感情】の増加にすることができる。",
  332. "吸血鬼の強大な力に対する憧れが膨れあがってくる。\nセッションの間、「誘惑」に対する抵抗判定にマイナス2の修正がつく。\nこの効果は累積しない。",
  333. "種族がらみのイヤなイベントが起こった。\n【モラル】の現在値を0にし、その状態でセッションを開始する。",
  334. "吸血鬼に転成を持ちかけられる。\n敵の吸血鬼に対する関係【深度】が1増加し、その状態でセッションを開始する。",
  335. "新しい友達が出来る。\n任意の年齢の協力者を、狩人のプレイヤーが作成する。\nレベルは1とすること。\nこの協力者はセッションに登場し、獲得すれば使用できる。"
  336. ]
  337. ),
  338. "ST" => DiceTable::Table.new(
  339. "シーン表",
  340. "2D6",
  341. [
  342. "どこまでも広がる荒野。風が吹き抜けていく。",
  343. "血まみれの惨劇の跡。いったい誰がこんなことを?",
  344. "都市の地下。かぼそい明かりがコンクリートを照らす。",
  345. "豪華な調度が揃えられた室内。くつろぎの空間を演出。",
  346. "普通の道端。様々な人が道を行き交う。",
  347. "明るく浮かぶ月の下。暴力の気配が満ちていく。",
  348. "打ち捨てられた廃墟。荒れ果てた景色に心も荒む。",
  349. "生活の様子が色濃く残る部屋の中。誰の部屋だろう?",
  350. "喧しい飲食店。騒ぐ人々に紛れつつ事態は進行する。",
  351. "ざわめく木立。踊る影。",
  352. "高い塔の上。都市を一望できる。"
  353. ]
  354. ),
  355. "MIT" => DiceTable::Table.new(
  356. "軽度狂気表",
  357. "1D6",
  358. [
  359. "【誇大妄想】(判定に失敗するたびに【感情】が1増加する。)",
  360. "【記憶喪失】(【幸福】の修復判定にマイナス2の修正。)",
  361. "【こだわり】(戦闘中の行動を「パス」以外で一つ選択し、その行動をすると【感情】が6増加する。)",
  362. "【お守り中毒】(「幸運のお守り」を装備していない場合、全ての2d6判定にマイナス1の修正。)",
  363. "【不死幻想】(自分が受けるダメージが全て1増加する。)",
  364. "【血の飢え】(戦闘中に最低1体でも死亡させないと、戦闘終了時に【感情】10増加。【激情】は獲得できない。)"
  365. ]
  366. ),
  367. "SIT" => DiceTable::Table.new(
  368. "重度狂気表",
  369. "1D6",
  370. [
  371. "【幸福依存】(【幸福】を一つ選択し、その【幸福】が結果フェイズに失われたとき、死亡する。)",
  372. "【見えない友達】(自分の関わる「関係を深める」判定にマイナス3の修正がつく。)",
  373. "【臆病】(自分の行う妨害判定にマイナス2の修正がつく。)",
  374. "【陰謀論】(「幸福を味わう」判定にマイナス3の修正がつく。)",
  375. "【指令受信】(追跡フェイズBでの自分の行動は、可能な範囲でGMが決定する。)",
  376. "【猜疑心】(自分が「連携攻撃」を行うとき、関係の【深度】をダメージに加えられない。)"
  377. ]
  378. ),
  379. }.merge(TABLES_WITH_BLOOD_MOON).freeze
  380. 1 register_prefix(RTT.prefixes, TABLES.keys)
  381. end
  382. end
  383. end

lib/bcdice/game_system/BloodMoon.rb

100.0% lines covered

90.0% branches covered

28 relevant lines. 28 lines covered and 0 lines missed.
10 total branches, 9 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/BloodCrusade"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class BloodMoon < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'BloodMoon'
  8. # ゲームシステム名
  9. 1 NAME = 'ブラッドムーン'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'ふらつとむうん'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・各種表
  15.  ・関係属性表 RAT
  16.  ・導入タイプ決定表(ノーマル) IDT
  17.  ・導入タイプ決定表(ハード込み) ID2T
  18.  ・シーン表 ST
  19.  ・先制判定指定特技表 IST
  20.  ・身体部位決定表   BRT
  21.  ・自信幸福表     CHT
  22.  ・地位幸福表     SHT
  23.  ・日常幸福表     DHT
  24.  ・人脈幸福表     LHT
  25.  ・退路幸福表     EHT
  26.  ・ランダム全特技表  AST
  27.  ・軽度狂気表     MIT
  28.  ・重度狂気表     SIT
  29. ・D66ダイスあり
  30. INFO_MESSAGE_TEXT
  31. 1 def initialize(command)
  32. 43 super(command)
  33. 43 @sort_add_dice = true
  34. 43 @d66_sort_type = D66SortType::ASC
  35. 43 @round_type = RoundType::CEIL # 端数切り上げに設定
  36. end
  37. # ゲーム別成功度判定(2D6)
  38. 1 def result_2d6(total, dice_total, _dice_list, cmp_op, target)
  39. 7 else: 7 then: 0 return nil unless cmp_op == :>=
  40. 7 then: 2 if dice_total <= 2
  41. 2 else: 5 Result.fumble("ファンブル(【余裕】が 0 に)")
  42. 5 then: 2 elsif dice_total >= 12
  43. 2 else: 3 Result.critical("スペシャル(【余裕】+3)")
  44. 3 then: 1 elsif target == '?'
  45. 1 else: 2 Result.nothing
  46. 2 then: 1 elsif total >= target
  47. 1 Result.success("成功")
  48. else: 1 else
  49. 1 Result.failure("失敗")
  50. end
  51. end
  52. 1 def eval_game_system_specific_command(command)
  53. 35 return roll_tables(command, TABLES) || BloodCrusade::RTT.roll_command(randomizer, command)
  54. end
  55. TABLES = {
  56. 1 "ST" => DiceTable::Table.new(
  57. "シーン表",
  58. "2D6",
  59. [
  60. "どこまでも広がる荒野。風が吹き抜けていく。",
  61. "血まみれの惨劇の跡。いったい誰がこんなことを?",
  62. "都市の地下。かぼそい明かりがコンクリートを照らす。",
  63. "豪華な調度が揃えられた室内。くつろぎの空間を演出。",
  64. "普通の道端。様々な人が道を行き交う。",
  65. "明るく浮かぶ月の下。暴力の気配が満ちていく。",
  66. "打ち捨てられた廃墟。荒れ果てた景色に心も荒む。",
  67. "生活の様子が色濃く残る部屋の中。誰の部屋だろう?",
  68. "にぎやかな飲食店。騒ぐ人々に紛れつつ事態は進行する。",
  69. "ざわめく木立。踊る影。",
  70. "高い塔の上。都市を一望できる。"
  71. ]
  72. ),
  73. "MIT" => DiceTable::Table.new(
  74. "軽度狂気表",
  75. "1D6",
  76. [
  77. "【誇大妄想】(判定に失敗するたびに【テンション】が1増加する。)",
  78. "【記憶喪失】(【幸福】の修復判定にマイナス2の修正。)",
  79. "【こだわり】(戦闘中の行動を「パス」以外で一つ選択し、その行動をすると【テンション】が6増加する。)",
  80. "【お守り中毒】(「幸運のお守り」を装備していない場合、全ての2d6判定にマイナス1の修正。)",
  81. "【不死幻想】(自分が受けるダメージが全て1増加する。)",
  82. "【血の飢え】(戦闘中、ラウンドごとに他のキャラクターにダメージを与えないと、ラウンド終了時に【テンション】4増加。)"
  83. ]
  84. ),
  85. "SIT" => DiceTable::Table.new(
  86. "重度狂気表",
  87. "1D6",
  88. [
  89. "【幸福依存】(【幸福】を一つ選択し、その【幸福】が結果フェイズに失われたとき、死亡する。)",
  90. "【見えない友達】(交流判定にマイナス3の修正がつく。)",
  91. "【臆病】(自分の行う妨害判定にマイナス2の修正がつく。)",
  92. "【陰謀論】(休息判定にマイナス3の修正がつく。)",
  93. "【指令受信】(メインフェイズの3サイクル目の自分のシーンでは、可能な範囲でGMが行動を決定する。)",
  94. "【猜疑心】(自分が「連携攻撃」を行うとき、関係の【深度】をダメージに加えられない。)"
  95. ]
  96. ),
  97. "CHT" => DiceTable::Table.new(
  98. "自信幸福表",
  99. "1D6",
  100. [
  101. "【戦闘能力】あなたはハンターとしての自分の戦闘能力に自信を持っています。たとえ負けようとも、それは運か相手か仲間が悪かったので、あなたの戦闘能力が低いわけではありません。",
  102. "【美貌】あなたは自分が美しいことを知っています。他人もあなたを美しいと思っているはず。鏡を見るたびに、あなたは自分の美しさに惚れ惚れしてしまいます。",
  103. "【血筋】あなたは名家の血を引く者です。祖先の栄光を背負い、家門の名誉を更に増すために、偉業をなす運命にあります。または、普通にいい家族に恵まれているのかもしれません。",
  104. "【趣味の技量】あなたは趣味の分野では第一人者です。必ずしも名前が知れ渡っているわけではありませんが、どんな相手にも負けない自信があります。どんな趣味かは自由です。",
  105. "【仕事の技量】職場で最も有能なもの、それがあなたです。誰もあなたの仕事の量とクオリティを超えられません。どんな仕事をしているかは自由に決めて構いません。",
  106. "【長生き】あなたはハンターとしてかなりの年月を過ごしてきたが、まだ死んでいません。これは誇るべきことです。そこらの若造には、まだまだ負けていません。"
  107. ]
  108. ),
  109. "SHT" => DiceTable::Table.new(
  110. "地位幸福表",
  111. "1D6",
  112. [
  113. "【役職】あなたは職場、あるいはハンターの組織のなかで高い階級についています。そのため、下にいるものには命令でき、相応の敬意を払われます。",
  114. "【英雄】あなたはかつて偉業を成し遂げたことがあり、誰でもそれを知っています。少々くすぐったい気もしますが、英雄として扱われるのは悪くありません。",
  115. "【お金持ち】あなたには財産があります。それも生半可な財産ではなく、人が敬意を払うだけの財産です。あなたはお金に困ることはなく、その幸せを知っています",
  116. "【特権階級】あなたは国が定める特権階級の一員です。王族や貴族をイメージするとわかりやすいでしょう。あなたは、どこに行っても、それ相応の扱いを受けることになります。",
  117. "【人格者】誰もが認める人格者としての評判を持っているため、あなたのところには悩みを抱えた人々が引きも切らずに押しかけてきます。大変ですが、ちょっと楽しい",
  118. "【リーダー】あなたは所属している何らかの組織を率いる立場にあります。会社の社長や、部活動の部長などです。あなたは求められてその地位にあります"
  119. ]
  120. ),
  121. "DHT" => DiceTable::Table.new(
  122. "日常幸福表",
  123. "1D6",
  124. [
  125. "【家】あなたの家はとても快適な空間です。コストと時間をかけて作り上げられた、あなたが居住するための空間。それはあなたの幸せの源なのです。",
  126. "【職場】あなたは仕事が楽しくて仕方ありません。意義ある仕事で払いも悪くなく、チームの仲間はみんないい奴ばかりです。残業は……ちょっとあるかもしれません。",
  127. "【行きつけの店】あなたには休みの日や職場帰りに立ち寄る行きつけの店があり、そこにいる時間は安らぎを感じることができます。店員とも顔見知りです。",
  128. "【ベッド】あなたは動物を飼っています。よく懐いた可愛い、またはかっこいい動物です。一緒に過ごす時間はあなたに幸せを感じさせてくれます",
  129. "【親しい隣人】おとなりさんやお向かいさん。よくお土産を渡したり、小さな子供を預かったりするような仲です。風邪を引いたときには、家事を手伝ってくれることも。",
  130. "【思い出】あなたは昔の思い出を心の支えにしています。何らかの幸せな記憶……それがあれば、この先にどんなつらいことが待っていても大丈夫でしょう。"
  131. ]
  132. ),
  133. "LHT" => DiceTable::Table.new(
  134. "人脈幸福表",
  135. "1D6",
  136. [
  137. "【理解ある家族】あなたの家族は、あなたがハンターであることを知ったうえで協力してくれます。これがどれほど稀なことかは、仲間に聞けば分かるでしょう。",
  138. "【有能な友人】あなたの友人は、吸血鬼の存在とあなたの本当の仕事を知っています。そして、直接戦うだけの技量はないものの、あなたの探索をサポートしてくれます。",
  139. "【愛する恋人】あなたには愛する人がいます。見つめあうだけで、あなたの心は舞い上がり……帰ってきません。この恋人を失うなんて、考えるだけでも恐ろしいことです。",
  140. "【同志の権力者】あなたには吸血鬼の存在を知りながら、奴らに屈していない権力者との繋がりがあります。様々な違法行為をはたらく際に、役に立つでしょう。",
  141. "【得がたい師匠】あなたは使う武器を学んだ師匠がいて、それを通して兄弟弟子とも繋がりがあります。過酷な訓練を経て、彼らとあなたには強い絆ができています。",
  142. "【可愛い子供】あなたには子供がいます。聡明で魅力的、しかも健康な……将来を嘱望される子供です。子供が掴む幸せな未来を思う時、あなたの顔には笑みが広がります。"
  143. ]
  144. ),
  145. "EHT" => DiceTable::Table.new(
  146. "退路幸福表",
  147. "1D6",
  148. [
  149. "【故郷の町】あなたは生まれ育った街を離れてハンターとして活動しています。いつの日かあの町へ帰る……その思いがあなたを戦いのなかで支えています。",
  150. "【待っている人】あなたがハンターをやめて、普通の暮らしに戻ることを待ちわびている人がいます。そして、あなたはその思いに応えたいと思っています。",
  151. "【就職先】あなたは吸血鬼狩りの報酬がなくなっても、すぐに入ることができる就職先があるので安心です。有能なのか過疎地域なのかは分かりませんが。",
  152. "【配偶者】あなたはハンターをやめたあとに家庭に入ろうと考えています。暮らしの設計はすでに済み、あとは実行するだけなのですが、なかなかそうはいきません。",
  153. "【大志】あなたがハンターとして活動しているのは、やむにやまれぬ事情があるからです。あなたには「本当にやりたかったこと」があり、いつかその夢をかなえる気でいます。",
  154. "【空想の王国】あなたには辛いことがあると白昼夢にふける、あるいは物語に没入する癖があり、そのときには非常に幸せな気分になることができます。"
  155. ]
  156. ),
  157. "ID2T" => DiceTable::D66Table.new(
  158. "導入タイプ決定表(ハード込み)",
  159. D66SortType::ASC,
  160. {
  161. 11 => "依頼\n《概要》 ハンターは任意のキャラクターに他のハンターの【幸福】を守るように依頼され、その依頼を受ける。\n《目的》 他のハンターの【幸福】のうち一つを結果フェイズまで破壊されないこと。この【幸福】は、ゲームマスターが指定する。\n《報酬》 経験値2",
  162. 12 => "防衛\n《概要》 ハンターは今回の敵となるモンスターに【幸福】を狙われている。モンスターを倒さなければ【幸福】を守る事は出来ない。\n《目的》 自分の獲得している【幸福】のうち一つを結果フェイズで失わないこと。この【幸福】はゲームマスターが指定する。\n《報酬》 経験値2",
  163. 13 => "復讐\n《概要》 ハンターは今回の敵となるモンスターに負けたことがある。戦闘に敗北したのか、それとも【幸福】を壊されたのか。いずれにせよ、復讐の時だ。\n《目的》 結果フェイズまでにモンスターを無力化すること。\n《報酬》 経験値2",
  164. 14 => "関係\n《概要》 ハンターは、特定の人物が参加しているから、という理由で狩りに参加する。憧れているのかライバルなのか、単に仲がいいのかは自由。\n《目的》 結果フェイズの時点で他のハンターのうち一人との関係が、お互いに【深度】3以上になっていること。対象のハンターはシーンプレイヤーが決定する。\n《報酬》 経験値2",
  165. 15 => "挑戦\n《概要》 ハンターは今回の敵となるモンスターのことをなんらかの理由で知り、自分から戦いに赴く。\n《目的》 結果フェイズまでハンター全員が生き残り、かつ、フォロワーやモンスターに変化していないこと。\n《報酬》 経験値2",
  166. 16 => "救済\n《概要》 ハンターは今回の敵となるフォロワーのうち一人を救うために戦う。\n《目的》 結果フェイズまでに対象のフォロワーを「説得」で無力化する。このフォロワーはシーンプレイヤーが決定する。\n《報酬》 経験値2",
  167. 22 => "復調\n 《概要》 ハンターは正気を取り戻し、【狂気】を癒すために戦う。\n《目的》 結果フェイズまでに自分の【狂気】を2減らす。\n《報酬》 経験値2",
  168. 23 => "撃滅 \n《概要》 ハンターは狩りの対象であるモンスターを倒すために育成されていたり、モンスターに【幸福】を全て破壊された過去を持っている。\n《目的》 モンスターを自分で無力化する。\n《報酬》 経験値6",
  169. 24 => "競争 \n《概要》 ハンターは自分で決めたライバルに勝つために狩りを行う。\n《目的》 他のプレイヤーのハンターからライバルを一人選ぶ。結果フェイズの段階で、ライバルよりも多くのモンスターとフォロワーを攻撃で倒している事。このライバルはシーンプレイヤーが選択する。\n《報酬》 経験値6",
  170. 25 => "育成 \n《概要》 ハンターは仲間を成長させるために狩りに出る。\n《目的》 他の狩人すべてに導入タイプの目的を達成させる。\n《報酬》 達成した人数+2の経験値",
  171. 26 => "窮乏 \n《概要》 ハンターは貧乏なので、金のために狩りをしなければならない。\n《目的》 自分が装備しているアイテムから一つを対象として選ぶ。対象は即座に破壊される。そのうえで、結果フェイズまで対象が書いてあったアイテム欄を使用しない。この対象はシーンプレイヤーが選択する。\n《報酬》 経験値6",
  172. 33 => "泰然 \n《概要》 ハンターはクールでかっこいい自分のスタイルを守るために狩りをする。\n《目的》 結果フェイズまで【激情】を使用しない。\n《報酬》 経験値8",
  173. 34 => "対話 \n《概要》 ハンターはモンスターと話をするために追いかけていく。\n《目的》 モンスターに対する関係【深度】が2以上になっている状態で決戦フェイズに入る。\n《報酬》 経験値8",
  174. 35 => "完勝 \n《概要》 ハンターは今回の敵となるモンスターに勝ったことがある。今度こそ、とどめを刺すのだ。\n《目的》 部位ダメージを受けずにモンスターを無力化する。\n《報酬》 経験値4",
  175. 36 => "依頼(ハード) \n《概要》 ハンターは任意のキャラクターに他のハンターの【幸福】を守るように依頼され、その依頼を受ける。\n《目的》 他のハンターの【幸福】を一つも結果フェイズまで破壊されないこと。対象となるハンターは、ゲームマスターが指定する。\n《報酬》 経験値4",
  176. 44 => "防衛(ハード) \n《概要》 ハンターは今回の敵となるモンスターに自分の【幸福】を狙われている。モンスターを倒さなければ、【幸福】を守ることはできない。\n《目的》 自分の獲得している【幸福】を一つも結果フェイズで失わないこと。\n《報酬》 経験値4",
  177. 45 => "復讐(ハード) \n《概要》 ハンターは今回の敵となるモンスターに負けたことがある。戦闘に敗北したのか、それとも、【幸福】を壊されたのか。いずれにせよ、復讐の時だ。\n《目的》 結果フェイズまでにモンスターとフォロワー全てを攻撃で倒すこと。自分の攻撃でなくてもかまわない。\n《報酬》 経験値6",
  178. 46 => "関係(ハード) \n《概要》 ハンターは、特定の人物が参加しているから、という理由で狩りに参加する。憧れているのかライバルなのか、単に仲がいいのかは自由。\n《目的》 結果フェイズの時点で他のハンターのうち一人との関係が、お互いに【深度】5になっていること。対象のハンターはシーンプレイヤーが決定する。\n《報酬》 経験値4",
  179. 55 => "挑戦(ハード) \n《概要》 ハンターは今回の敵となるモンスターのことをなんらかの理由で知り、自分から戦いに赴く。\n《目的》 結果フェイズまでハンター全員が一度も無力化されずに生き残り、かつ、フォロワーやモンスターに変化していないこと。\n《報酬》 経験値6",
  180. 56 => "救済(ハード) \n《概要》 ハンターは今回の敵となるフォロワー全員を救うために戦う。\n《目的》 結果フェイズまでにフォロワー全員を「説得」で無力化する。\n《報酬》 経験値6",
  181. 66 => "振り直し"
  182. }
  183. ),
  184. "IDT" => DiceTable::Table.new(
  185. "導入タイプ決定表(ノーマル)",
  186. "1D6",
  187. [
  188. "依頼\n《概要》 ハンターは任意のキャラクターに他のハンターの【幸福】を守るように依頼され、その依頼を受ける。\n《目的》 他のハンターの【幸福】のうち一つを結果フェイズまで破壊されないこと。この【幸福】は、ゲームマスターが指定する。\n《報酬》 経験値2",
  189. "防衛\n《概要》 ハンターは今回の敵となるモンスターに【幸福】を狙われている。モンスターを倒さなければ【幸福】を守る事は出来ない。\n《目的》 自分の獲得している【幸福】のうち一つを結果フェイズで失わないこと。この【幸福】はゲームマスターが指定する。\n《報酬》 経験値2",
  190. "復讐\n《概要》 ハンターは今回の敵となるモンスターに負けたことがある。戦闘に敗北したのか、それとも【幸福】を壊されたのか。いずれにせよ、復讐の時だ。\n《目的》 結果フェイズまでにモンスターを無力化すること。\n《報酬》 経験値2",
  191. "関係\n《概要》 ハンターは、特定の人物が参加しているから、という理由で狩りに参加する。憧れているのかライバルなのか、単に仲がいいのかは自由。\n《目的》 結果フェイズの時点で他のハンターのうち一人との関係が、お互いに【深度】3以上になっていること。対象のハンターはシーンプレイヤーが決定する。\n《報酬》 経験値2",
  192. "挑戦\n《概要》 ハンターは今回の敵となるモンスターのことをなんらかの理由で知り、自分から戦いに赴く。\n《目的》 結果フェイズまでハンター全員が生き残り、かつ、フォロワーやモンスターに変化していないこと。\n《報酬》 経験値2",
  193. "救済\n《概要》 ハンターは今回の敵となるフォロワーのうち一人を救うために戦う。\n《目的》 結果フェイズまでに対象のフォロワーを「説得」で無力化する。このフォロワーはシーンプレイヤーが決定する。\n《報酬》 経験値2"
  194. ]
  195. ),
  196. "RAT" => DiceTable::D66Table.new(
  197. "関係属性表",
  198. D66SortType::NO_SORT,
  199. {
  200. 11 => "愛情",
  201. 12 => "憧れ",
  202. 13 => "怒り",
  203. 14 => "悲しみ",
  204. 15 => "感謝",
  205. 16 => "期待",
  206. 21 => "憧れ",
  207. 22 => "共感",
  208. 23 => "恐怖",
  209. 24 => "嫌悪",
  210. 25 => "困惑",
  211. 26 => "罪悪感",
  212. 31 => "怒り",
  213. 32 => "恐怖",
  214. 33 => "殺意",
  215. 34 => "嫉妬",
  216. 35 => "憎悪",
  217. 36 => "忠義",
  218. 41 => "悲しみ",
  219. 42 => "嫌悪",
  220. 43 => "嫉妬",
  221. 44 => "不信感",
  222. 45 => "侮蔑",
  223. 46 => "保護欲",
  224. 51 => "感謝",
  225. 52 => "困惑",
  226. 53 => "憎悪",
  227. 54 => "侮蔑",
  228. 55 => "満足感",
  229. 56 => "友情",
  230. 61 => "期待",
  231. 62 => "罪悪感",
  232. 63 => "忠義",
  233. 64 => "保護欲",
  234. 65 => "友情",
  235. 66 => "喜び"
  236. }
  237. ),
  238. }.merge(BloodCrusade::TABLES_WITH_BLOOD_MOON).freeze
  239. 1 register_prefix(BloodCrusade::RTT.prefixes, TABLES.keys)
  240. end
  241. end
  242. end

lib/bcdice/game_system/Bloodorium.rb

96.67% lines covered

87.5% branches covered

30 relevant lines. 29 lines covered and 1 lines missed.
8 total branches, 7 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Bloodorium < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Bloodorium'
  7. # ゲームシステム名
  8. 1 NAME = 'ブラドリウム'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ふらとりうむ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・ダイスチェック xDC+y
  14.  【ダイスチェック】を行う。《トライアンフ》を結果に自動反映する。
  15.  x: ダイス数
  16.  y: 結果への修正値 (省略可)
  17. INFO_MESSAGE_TEXT
  18. 1 register_prefix('\d+DC')
  19. 1 def eval_game_system_specific_command(command)
  20. 16 dicecheck(command)
  21. end
  22. 1 private
  23. 1 def dicecheck(command)
  24. 16 parser = Command::Parser.new("DC", round_type: @round_type).has_prefix_number.restrict_cmp_op_to(nil)
  25. 16 parsed = parser.parse(command)
  26. 16 else: 16 then: 0 unless parsed
  27. return nil
  28. end
  29. 16 dice_list = @randomizer.roll_barabara(parsed.prefix_number, 6).sort
  30. 16 dice_value = dice_list.max
  31. 16 values_count = dice_list
  32. .group_by(&:itself)
  33. .transform_values(&:length)
  34. 16 triumph = values_count.values.max
  35. 16 total = dice_value * triumph + parsed.modify_number
  36. sequence = [
  37. 16 "(#{parsed})",
  38. "[#{dice_list.join(',')}]#{Format.modifier(parsed.modify_number)}",
  39. 16 then: 8 else: 8 ("《トライアンフ》(*#{triumph})" if triumph > 1),
  40. 16 then: 12 else: 4 (total_expr(dice_value, triumph, parsed.modify_number) if total != dice_value),
  41. total,
  42. ].compact
  43. 16 return Result.new.tap do |r|
  44. 16 r.critical = triumph > 1
  45. 16 r.text = sequence.join(" > ")
  46. end
  47. end
  48. 1 def total_expr(dice_value, triumph, modify_number)
  49. 12 then: 8 else: 4 formated_triumph = triumph > 1 ? "*#{triumph}" : nil
  50. 12 return "#{dice_value}#{formated_triumph}#{Format.modifier(modify_number)}"
  51. end
  52. end
  53. end
  54. end

lib/bcdice/game_system/CardRanker.rb

100.0% lines covered

93.75% branches covered

37 relevant lines. 37 lines covered and 0 lines missed.
16 total branches, 15 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class CardRanker < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'CardRanker'
  7. # ゲームシステム名
  8. 1 NAME = 'カードランカー'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'かあとらんかあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ランダムでモンスターカードを選ぶ (RM) (RTTn n:色番号、省略可能)
  14. ランダム分野表 RCT
  15. 特定のモンスターカードを選ぶ (CMxy x:色、y:番号)
  16.  白:W、青:U、緑:V、金:G、赤:R、黒:B
  17.  例)CMW2→白の2:白竜 CMG12→金の12:土精霊
  18. 場所表 (ST)
  19. 街中場所表 (CST)
  20. 郊外場所表 (OST)
  21. 学園場所表 (GST)
  22. 運命表 (DT)
  23. 大会運命表 (TDT)
  24. 学園運命表 (GDT)
  25. 崩壊運命表 (CDT)
  26. INFO_MESSAGE_TEXT
  27. 1 def initialize(command)
  28. 44 super(command)
  29. 44 @sort_add_dice = true
  30. 44 @d66_sort_type = D66SortType::ASC
  31. end
  32. # ゲーム別成功度判定(2D6)
  33. 1 def result_2d6(total, dice_total, _dice_list, cmp_op, target)
  34. 7 else: 7 then: 0 return nil unless cmp_op == :>=
  35. 7 then: 2 if dice_total <= 2
  36. 2 else: 5 Result.fumble("ファンブル")
  37. 5 then: 2 elsif dice_total >= 12
  38. 2 else: 3 Result.critical("スペシャル > " + RTT.roll_command(@randomizer, "RM"))
  39. 3 then: 1 elsif target == "?"
  40. 1 else: 2 Result.nothing
  41. 2 then: 1 elsif total >= target
  42. 1 Result.success("成功")
  43. else: 1 else
  44. 1 Result.failure("失敗")
  45. end
  46. end
  47. 1 def eval_game_system_specific_command(command)
  48. 37 roll_tables(command, TABLES) || get_monster(command) || RTT.roll_command(randomizer, command)
  49. end
  50. 1 COLOR_TABLE = ['W', 'U', 'V', 'G', 'R', 'B'].freeze
  51. 1 RTT = DiceTable::SaiFicSkillTable.new([
  52. ['白', ['白竜', '僧侶', '格闘家', '斧使い', '剣士', '槍士', '歩兵', '弓兵', '砲兵', '天使', '軍神']],
  53. ['青', ['水竜', '魚', '魚人', 'イカ', '蟹', '探偵', '海賊', '魔術師', '使い魔', '雲', '水精霊']],
  54. ['緑', ['緑竜', 'ワーム', '鳥人', '鳥', '獣', '獣人', 'エルフ', '妖精', '昆虫', '植物', '森精霊']],
  55. ['金', ['金竜', '宝石', '岩石', '鋼', '錬金術師', '魔法生物', 'ドワーフ', '機械', '運命', '女神', '土精霊']],
  56. ['赤', ['火竜', '竜人', '恐竜', '戦車', '蛮族', '小鬼', '大鬼', '巨人', '雷', '炎', '火精霊']],
  57. ['黒', ['黒竜', '闇騎士', '怪物', '忍者', '妖怪', '蝙蝠', '吸血鬼', '不死者', '幽霊', '悪魔', '邪神']],
  58. ], rtt: "RM", rtt_format: "ランダムモンスター選択(%<category_dice>d,%<row_dice>d) > %<text>s", s_format: "%<category_name>sの%<row_dice>d:%<skill_name>s")
  59. 1 def get_monster(command)
  60. 19 m = command.match(/^CM(\w)(\d+)$/i)
  61. 19 else: 9 then: 10 return nil unless m
  62. 9 cat = COLOR_TABLE.index(m[1])
  63. 9 row_dice = m[2].to_i
  64. 9 else: 8 then: 1 return nil unless cat
  65. 8 else: 6 then: 2 return nil unless row_dice.between?(2, 12)
  66. 6 skill = RTT.categories[cat].skills[row_dice - 2]
  67. 6 return "モンスター選択 > #{skill}"
  68. end
  69. TABLES = {
  70. 1 "BFT" => DiceTable::Table.new(
  71. "バトルフィールド表",
  72. "1D6",
  73. [
  74. "ハイ・アンティ/戦闘フェイズの終了時、勝者は通常習得できるモンスターカード一つに加えて、もう一つ敗者からモンスターカードを選んで手に入れることができる。//通常よりも多くのカードを賭けの対象にするルール。",
  75. "バーニング/ラウンドの終了時、すべてのキャラクターは【LP】現在値を3点失う。//マグマの近くや極寒の地など体力を削られるような過酷な環境で行われるルール。",
  76. "ノーマル/特に影響なし。//通常のルール。",
  77. "ハード/すべてのキャラクターの判定にプラス1の修正を加える。また、ラウンド終了時にすべてのキャラクターはモンスターカードを一つ選んで破壊状態(ルールブックP187参照)にしなければならない。//風の強い場所や水中など、カードを扱いにくい環境でのルール。",
  78. "スピード/モンスターカードのリスクが1高いものとして扱われる。また、判定に失敗した場合、速度から振り落とされて1D6のダメージを受ける。//バイクやローラーボードなどを使って行われる高速カードバトルルール。",
  79. "デスルール/戦闘フェイズでも死亡判定が発声する。また、戦闘不能になったキャラクターは即座に死亡判定を行う。ただし、攻撃を行った側がデスルールを使用しないことを選択すれば、死亡判定は発生しない。//モンスターによって実際のダメージを与える、死の危険性があるルール。"
  80. ]
  81. ),
  82. "CDT" => DiceTable::Table.new(
  83. "崩壊運命表",
  84. "1D6",
  85. [
  86. "レジェンドカードがあなたを崩壊する大地に呼び寄せた。暴虐な振る舞いをするダークランカーを倒すことをレジェンドカードは望んでいる。",
  87. "あなたはひょんなことから人を助けた。すると、あなたはいつの間にか救世主と呼ばれる存在になっていた、救世主であるあなたに人々は懇願する。ダークランカーを倒してくれと。",
  88. "あなたの住むところはダークランカーの力が及ばない楽園であった。しかし、楽園はダークランカー一味の襲撃にあい、あなただけが生き残ってしまった。楽園を出たあなたは戦いを決意する。",
  89. "世の中は変わった。だが、愛する人(もしくは愛する物や家族)は健在だ。あなたは愛する人を護るためにも、ダークランカーを倒すべく動き始めた。",
  90. "あなたはこの世界が好きだ。それはどんな理由でもよい。しかし、ダークランカーが持つダークカードはこの世界を壊す。ならば、倒してこの世界を守らねばならない。",
  91. "崩壊していく大地。泣き叫ぶ人々の声。あなたはこの状況を作ったのが、あなたの身内であると知る。ダークカードの手から身内を救うためにも、あなたはカードを手にとった。"
  92. ]
  93. ),
  94. "CST" => DiceTable::Table.new(
  95. "街中場所表",
  96. "1D6",
  97. [
  98. "カードショップ/ソウルカードを遊ぶ者たちが集まる場所。プレイスペースもあれば、カードの販売もしている。",
  99. "ビル街/ビルが立ち並ぶ街。ビジネスマンが忙しなく動き、チェーン店が多く見られる。",
  100. "駅前/人が集まる駅前。電車から降りてくる人は多く、今日も人と人がすれ違う。",
  101. "食事処/レストランから大衆食堂、喫茶店やバーなど、食事は人の活力であり、カードランカーにも元気は必要だ。",
  102. "道路/長く広い道路。車と人が通過していく場所だが、時おりトラブルを抱えたカードランカー同士が戦っている。",
  103. "プール/都会にあるプール。都会の生活に疲れた人々が集まる場所。時おり、ソウルカードの戦いも見られる。"
  104. ]
  105. ),
  106. "DT" => DiceTable::Table.new(
  107. "運命表",
  108. "1D6",
  109. [
  110. "あなたが欲しているカードはダークランカーが持っているかもしれないという情報を掴んだ。ダークランカーを倒し、アンティルールでカードを手に入れなければならない。",
  111. "ダークランカーとなった人物とあなたはカード仲間であったが、ある日見たその人物はダークカードの力にとり憑かれて豹変していた。あなたは仲間をカードによって救うため、戦いを決意した。",
  112. "ダークランカーはあなたの仲間や身内、大切なモノを傷つけた(壊した)。あなたの大切なものを傷つけたダークランカー、許しはしない。",
  113. "あなたの持つレジェンドカードが、ダークランカーもしくは他のレジェンドカードが出現することを察知した。レジェンドカードに導かれるまま、キミはダークランカー(レジェンドカード)を探し始めた。",
  114. "カードランカーの組織やソウルカードの安定を願う人からそのダークランカーを倒すように依頼を受けた、あなたはその仕事を受ける価値があると思った。そう思った理由は報酬でもいいし、あなたの流儀でもよい。",
  115. "ダークランカーとあなたは偶然にも出会ってしまった。ダークランカーは危険な存在だ。見てしまった以上、放っておくわけにはいかない。"
  116. ]
  117. ),
  118. "GDT" => DiceTable::Table.new(
  119. "学園運命表",
  120. "1D6",
  121. [
  122. "あなたが過ごしているクラスや寮、部活が潰されそうになった。その裏にはダークランカーの影響があるらしい。",
  123. "学園の偉い人から、カードランカーであるあなたに調査依頼が入った。どうやらダークランカーが学園に干渉しているとのこと。",
  124. "学園内のカードが奪われた。ダークランカーの影響だろう。大切にされていたカードを取り戻すために、あなたは立ち上がった。",
  125. "学内に邪悪な影響を受けたカードが入り込んでいた。おそらく、ダークランカーの仕業に違いない。",
  126. "ダークランカーによって被害を受けた生徒があなたに相談してきた。あなたはその生徒のためにもダークランカーの調査に乗り出した。",
  127. "ダークランカーの影響を受け、授業や部活動はまともにできなくなってしまった。あなたは元の学校生活を再開させるためにも、調査を始めた。"
  128. ]
  129. ),
  130. "OST" => DiceTable::Table.new(
  131. "郊外場所表",
  132. "1D6",
  133. [
  134. "カードショップ/ソウルカードを遊ぶ者たちが集まる場所。少し治安と客層が悪いが、賞金稼ぎも集まる。",
  135. "荒野/動植物も少なく、ピリピリとした雰囲気のある場所。",
  136. "遺跡/古代の遺跡。レジェンドカードやモンスターカードはこうした場所に発生したり、隠されていたりすることが多い。",
  137. "平原/どこまでも続く平原。動物も温厚であり、生い茂る草花が柔らかな印象を与える場所だ。",
  138. "山岳/険しい道が続く山。カードの精霊たちが生息していることもあるが、カード山賊団には気をつけねばならない。",
  139. "海川/海や川。山と同じくカードの精霊たちが住んでいる場所だ。安らげる場所でもあり、休憩している人がソウルカードをしている。"
  140. ]
  141. ),
  142. "GST" => DiceTable::Table.new(
  143. "学園場所表",
  144. "1D6",
  145. [
  146. "購買/学生にとっては学園内で唯一買い物ができる場所。パンの他に、カードパックが売っている。",
  147. "グラウンド/体育館/運動するのに適した広い空間だが、同時にソウルカードをやるのにもうってつけの場所である。",
  148. "屋上/校舎の屋上は一部の生徒には人気のスポットだ。今日も強い風が彼らを迎えている。",
  149. "教室/日が昇っている間は、学生たちの声で賑やかな場所。夕暮れからは少し物哀しく、寂しい。",
  150. "校舎裏/学校の中でも珍しく人目につかない場所。不良たちがソウルカードをやっている姿が見られる。",
  151. "部活棟/部活をやる者のために用意された場所。しかし、サボってソウルカードをやっているところも。"
  152. ]
  153. ),
  154. "ST" => DiceTable::Table.new(
  155. "場所表",
  156. "1D6",
  157. [
  158. "カード系/ショップや大会の会場など、ソウルカードに関係がある場所。カードランカーたちも集まってくる。",
  159. "自然/公園や山など、自然の息吹が感じられる場所。耳を澄ませばカードの声も聞こえるかもしれない。",
  160. "神秘/古代の施設や、神社・教会などの神秘的な場所。レジェンドカードが隠されているかもしれない。",
  161. "安息/自宅など、安らげる空間。そこはあなたが安らげる場所であり、思い出の地なのかもしれない。",
  162. "街中/人々が住む街中。何気なく落ちているカードの中には、価値があるものもあるかも。",
  163. "水辺/プールや海岸など、水が近くに存在する場所。ひとまず、ここでひと息つけそうだ。"
  164. ]
  165. ),
  166. "TDT" => DiceTable::Table.new(
  167. "大会運命表",
  168. "1D6",
  169. [
  170. "あなたは友人と共に大会に出場した。しかし、友人はダークランカーによって倒されてしまった。",
  171. "あなたは大会の商品を狙い、大会に出場した。だが、ダークランカーもそれを狙っているらしい。",
  172. "あなたは大会の運営者から、大会に関わっているダークランカーの撃破を依頼された。",
  173. "あなたはカードの導くままに、大会に関わってくるダークランカーの出現を察知した。",
  174. "あなたは大会の一選手として戦っていた。だが、謎の刺客によって襲われた。きっとダークランカーの仕業に違いない。",
  175. "あなたは大会に出場し、優勝候補と言われているカードランカーだ。だが、そんなキミをダークランカーは襲った。"
  176. ]
  177. ),
  178. "WT" => DiceTable::Table.new(
  179. "変調表",
  180. "1D6",
  181. [
  182. "猛毒/ラウンド終了時に【LP】の現在値を3点失う。また【LP】の現在値を回復できない。",
  183. "炎上/ラウンド終了時に、モンスターカードを一つ選び破壊状態にしなければならない。既に破壊状態になっているものは選べない。",
  184. "妨害/攻撃判定にマイナス2の修正を受ける。",
  185. "捕縛/ブロック判定にマイナス2の修正を受ける。",
  186. "召喚制限/「タイプ:補助」のモンスターカードを使用できない。",
  187. "暗闇/「タイプ:支援」のモンスターカードを使用できない。"
  188. ]
  189. ),
  190. }.freeze
  191. 1 register_prefix(RTT.prefixes, 'CM', TABLES.keys)
  192. end
  193. end
  194. end

lib/bcdice/game_system/CastleInGray.rb

100.0% lines covered

100.0% branches covered

33 relevant lines. 33 lines covered and 0 lines missed.
18 total branches, 18 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class CastleInGray < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "CastleInGray"
  7. # ゲームシステム名
  8. 1 NAME = "灰色城綺譚"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "はいいろしようきたん"
  11. 1 HELP_MESSAGE = <<~TEXT
  12. ■ 色占い (BnWm)
  13. n: 黒
  14. m: 白
  15. n, m は1~12の異なる整数
  16. 例) B12W7
  17. 例) B5W12
  18. ■ 悪意の渦による占い (MALn)
  19. n: 悪意の渦
  20. n は1~12の整数
  21. ■ その他
  22. ・感情表 ET
  23. ・暗示表(黒) BIT
  24. ・暗示表(白) WIT
  25. TEXT
  26. TABLES = {
  27. 1 "ET" => DiceTable::Table.new(
  28. "感情表",
  29. "1D12",
  30. [
  31. "友情(白)/敵視(黒)",
  32. "恋慕(白)/嫌悪(黒)",
  33. "信頼(白)/不信(黒)",
  34. "同情(白)/憐憫(黒)",
  35. "憧憬(白)/劣等感(黒)",
  36. "尊敬(白)/蔑視(黒)",
  37. "忠誠(白)/執着(黒)",
  38. "有用(白)/邪魔(黒)",
  39. "許容(白)/罪悪感(黒)",
  40. "羨望(白)/嫉妬(黒)",
  41. "共感(白)/拒絶(黒)",
  42. "愛情(白)/狂信(黒)"
  43. ]
  44. ),
  45. "BIT" => DiceTable::Table.new(
  46. "暗示表(黒)",
  47. "1D12",
  48. [
  49. "終わりなき夜に生まれつく者もあり",
  50. "悪意もて真実を語らば",
  51. "笑えども笑みはなし",
  52. "影より抜け出ることあたわじ",
  53. "心の赴くままに手をとれ",
  54. "時ならぬ嵐の過ぎ去るを待つ",
  55. "赦されぬと知るがゆえに",
  56. "見張りは持ち場を離れる",
  57. "誰もが盲いたる彷徨い人なり",
  58. "落ちる日を眺めるがごとく",
  59. "冷たく雨ぞ降りしきる",
  60. "今日は笑む花も明日には枯れゆく"
  61. ]
  62. ),
  63. "WIT" => DiceTable::Table.new(
  64. "暗示表(白)",
  65. "1D12",
  66. [
  67. "無垢なる者のみが真実を得る",
  68. "げに慈悲深きは沈黙なり",
  69. "懐かしき日々は去りぬ",
  70. "束の間に光さす",
  71. "迷える者に手を差し伸べよ",
  72. "嵐の前には静けさがある",
  73. "どうか責めないで",
  74. "灯した明かりを絶やさぬように",
  75. "目を開けて見よ",
  76. "淑やかに訪れる",
  77. "今こそ泣け、さもなくば二度と泣くな",
  78. "時が許す間に薔薇を摘め"
  79. ]
  80. ),
  81. }.freeze
  82. 1 register_prefix('B', 'MAL', TABLES.keys)
  83. 1 def eval_game_system_specific_command(command)
  84. 30 return roll_color(command) || roll_mal(command) || roll_tables(command, TABLES)
  85. end
  86. 1 def roll_color(command)
  87. 30 m = /^B(\d{1,2})W(\d{1,2})$/.match(command)
  88. 30 else: 11 then: 19 return nil unless m
  89. 11 black = m[1].to_i
  90. 11 white = m[2].to_i
  91. 11 else: 7 then: 4 return nil unless black.between?(1, 12) && white.between?(1, 12)
  92. 7 value = @randomizer.roll_once(12)
  93. 7 then: 1 else: 6 if black == white
  94. 1 return color_text(black, white, value, '白と黒は重ねられません')
  95. end
  96. 6 then: 2 if white > black
  97. 2 then: 1 else: 1 return color_text(black, white, value, black <= value && value < white ? '黒' : '白')
  98. else: 4 else
  99. 4 then: 2 else: 2 return color_text(black, white, value, white <= value && value < black ? '白' : '黒')
  100. end
  101. end
  102. 1 def color_text(black, white, value, result)
  103. 7 return "色占い(黒#{black}白#{white}) > [#{value}] > #{result}"
  104. end
  105. 1 def roll_mal(command)
  106. 23 m = /^MAL(\d{1,2})$/i.match(command)
  107. 23 else: 10 then: 13 return nil unless m
  108. 10 mal = m[1].to_i
  109. 10 else: 8 then: 2 return nil unless mal.between?(1, 12)
  110. 8 value = @randomizer.roll_once(12)
  111. 8 then: 5 else: 3 result = value <= mal ? '黒' : '白'
  112. 8 return "悪意の渦(#{mal}) > [#{value}] > #{result}"
  113. end
  114. end
  115. end
  116. end

lib/bcdice/game_system/ChaosFlare.rb

96.25% lines covered

90.0% branches covered

80 relevant lines. 77 lines covered and 3 lines missed.
40 total branches, 36 branches covered and 4 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class ChaosFlare < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'ChaosFlare'
  7. # ゲームシステム名
  8. 1 NAME = 'カオスフレア'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'かおすふれあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. 判定
  14. CF
  15. 書式: [ダイスの数]CF[修正値][@クリティカル値][#ファンブル値][>=目標値]
  16. CF以外は全て省略可能
  17. 例:
  18. - CF 2D6,クリティカル値12,ファンブル値2で判定
  19. - CF+10@10 修正値+10,クリティカル値10で判定
  20. - CF+10#3 修正値+10,ファンブル値3で判定
  21. - CF+10>=10 目標値を指定した場合、差分値も出力する
  22. - 3CF+10@10#3>=10 3D6での判定
  23. - CF@9#3+8>=10
  24. 2D6
  25. ファンブル値2で判定する。クリティカルの判定は行われない。
  26. 目標値が設定された場合、差分値を出力する。
  27. - 2D6+4>=10
  28. 各種表
  29. FT: 因縁表
  30. FTx: 数値を指定すると因果表の値を出力する
  31. - FT -> 11から66の間でランダム決定
  32. - FT23 -> 23の項目を出力
  33. - FT0
  34. - FT7
  35. INFO_MESSAGE_TEXT
  36. 1 register_prefix('\d*CF', 'FT')
  37. # ゲーム別成功度判定(2D6)。以前の処理をそのまま残しています。
  38. 1 def result_2d6(total, dice_total, _dice_list, cmp_op, target)
  39. 7 else: 7 then: 0 return nil unless cmp_op == :>=
  40. 7 sequence = []
  41. 7 result = Result.new
  42. 7 then: 3 else: 4 if dice_total <= 2
  43. 3 total -= 20
  44. 3 sequence.push("ファンブル(-20)")
  45. 3 result.fumble = true
  46. end
  47. 7 then: 5 else: 2 if target != '?'
  48. 5 then: 3 if total >= target
  49. 3 sequence.push("成功")
  50. 3 result.success = true
  51. else: 2 else
  52. 2 sequence.push("失敗")
  53. 2 result.failure = true
  54. end
  55. 5 then: 4 else: 1 if total - target != 0
  56. 4 sequence.push("差分値#{total - target}")
  57. end
  58. end
  59. 7 then: 1 else: 6 return Result.nothing if sequence.empty?
  60. 6 result.text = sequence.join(" > ")
  61. 6 return result
  62. end
  63. 1 def eval_game_system_specific_command(command)
  64. 15 then: 5 if command.start_with? "FT"
  65. 5 roll_fate_table(command)
  66. else: 10 else
  67. 10 cf_roll(command)
  68. end
  69. end
  70. 1 private
  71. # 因縁表
  72. 1 def roll_fate_table(command)
  73. 5 m = /^FT(\d+)?/.match(command)
  74. 5 then: 3 if m[1]
  75. 3 num = m[1].to_i
  76. 3 then: 2 else: 1 if [0, 7].include?(num)
  77. 2 return "因果表(#{num}) > #{FATE_TABLE[num][0]}"
  78. end
  79. 1 dice1 = num / 10
  80. 1 dice2 = num % 10
  81. 1 then: 0 else: 1 if !(1..6).include?(dice1) || !(1..6).include?(dice2)
  82. return nil
  83. end
  84. else: 2 else
  85. 2 dice1 = @randomizer.roll_once(6)
  86. 2 dice2 = @randomizer.roll_once(6)
  87. end
  88. 3 index1 = dice1
  89. 3 index2 = (dice2 / 2) - 1
  90. 3 return "因果表(#{dice1}#{dice2}) > #{FATE_TABLE[index1][index2]}"
  91. end
  92. # カオスフレア専用コマンド
  93. # @param command [String]
  94. # @return [String, nil]
  95. 1 def cf_roll(command)
  96. 10 parser = Command::Parser.new(/\d*CF/, round_type: round_type)
  97. .enable_critical
  98. .enable_fumble
  99. 10 @cmd = parser.parse(command)
  100. 10 else: 10 then: 0 unless @cmd
  101. return nil
  102. end
  103. 10 then: 6 else: 4 times = @cmd.command == "CF" ? 2 : @cmd.command.to_i
  104. 10 critical = @cmd.critical || 12
  105. 10 fumble = @cmd.fumble || 2
  106. 10 @cmd.dollar = nil
  107. 10 then: 0 else: 10 if times < 0 || ![:>=, nil].include?(@cmd.cmp_op)
  108. return nil
  109. end
  110. 10 dice_list = @randomizer.roll_barabara(times, 6)
  111. 10 dice_total = dice_list.sum()
  112. 10 dice_list_text = dice_list.join(",")
  113. 10 is_critical = dice_total >= critical
  114. 10 is_fumble = dice_total <= fumble
  115. total =
  116. 10 then: 4 if is_critical
  117. 4 else: 6 30
  118. 6 then: 1 elsif is_fumble
  119. 1 -20
  120. else: 5 else
  121. 5 dice_total
  122. end
  123. 10 total += @cmd.modify_number
  124. sequence = [
  125. 10 "(#{@cmd.to_s(:after_modify_number)})",
  126. "#{dice_total}[#{dice_list_text}]",
  127. total.to_s,
  128. 10 then: 2 else: 8 ("0" if total < 0),
  129. 10 then: 4 else: 6 ("クリティカル" if is_critical),
  130. 10 then: 1 else: 9 ("ファンブル" if is_fumble),
  131. 10 then: 5 else: 5 ("差分値 #{difference(total)}" if @cmd.target_number),
  132. ].compact
  133. 10 return sequence.join(" > ")
  134. end
  135. # @param total [Integer] 合計値
  136. # @return [Integer] 差分値
  137. 1 def difference(total)
  138. 5 then: 1 if total < 0
  139. 1 -@cmd.target_number
  140. else: 4 else
  141. 4 total - @cmd.target_number
  142. end
  143. end
  144. # 表を振るのに使う定数的なやつ。
  145. FATE_TABLE = [
  146. 1 ["腐れ縁"],
  147. ["純愛", "親近感", "庇護"],
  148. ["信頼", "感服", "共感"],
  149. ["友情", "尊敬", "慕情"],
  150. ["好敵手", "期待", "借り"],
  151. ["興味", "憎悪", "悲しみ"],
  152. ["恐怖", "執着", "利用"],
  153. ["任意"]
  154. ].freeze
  155. end
  156. end
  157. end

lib/bcdice/game_system/CharonSanctions.rb

100.0% lines covered

83.33% branches covered

28 relevant lines. 28 lines covered and 0 lines missed.
6 total branches, 5 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class CharonSanctions < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "CharonSanctions"
  7. # ゲームシステム名
  8. 1 NAME = "カローン・サンクションズ"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "かろおんさんくしおんす"
  11. 1 HELP_MESSAGE = <<~TEXT
  12. ■ 判定
  13. nCSm>=t [判定]を行う。成功/不完全成功を判定。(p.111)
  14. n: ダイス数
  15. m: [難易度](省略時 4)
  16. t: [必要成功数](省略時 1)
  17. ■ 各種表
  18. ET 感情ワード(キャラクター)表(p.120)
  19. RT 襲撃表(p.146)
  20. TEXT
  21. 1 def eval_game_system_specific_command(command)
  22. 17 action_roll(command) ||
  23. roll_tables(command, TABLES)
  24. end
  25. 1 private
  26. 1 def action_roll(command)
  27. 17 parser = Command::Parser.new("CS", round_type: round_type)
  28. .has_prefix_number
  29. .enable_suffix_number
  30. .disable_modifier
  31. .restrict_cmp_op_to(nil, :>=)
  32. 17 cmd = parser.parse(command)
  33. 17 else: 13 then: 4 return nil unless cmd
  34. 13 times = cmd.prefix_number
  35. 13 then: 0 else: 13 return nil if times < 1
  36. 13 required = (cmd.suffix_number || 4).clamp(2, 6)
  37. 13 target = cmd.target_number || 1
  38. 13 dice_list = @randomizer.roll_barabara(times, 6)
  39. 39 count = dice_list.count { |i| i >= required }
  40. result =
  41. 13 then: 6 if count >= target
  42. 6 Result.success("成功")
  43. else: 7 else
  44. 7 Result.failure("不完全成功")
  45. end
  46. sequence = [
  47. 13 "(#{cmd})",
  48. "(#{times}B6>=#{required}[>=#{target}])",
  49. "[#{dice_list.join(',')}]",
  50. "成功数:#{count}",
  51. result.text
  52. ].compact
  53. 13 result.text = sequence.join(" > ")
  54. 13 result
  55. end
  56. TABLES = {
  57. 1 'ET' => DiceTable::D66RangeTable.new(
  58. '感情ワード(キャラクター)表',
  59. {
  60. 11..12 => '愛情/あなたは、対象のキャラクターに愛情を抱いています。',
  61. 13..14 => '家族/あなたは、対象のキャラクターをまるで家族のように感じています。',
  62. 15..16 => '腐れ縁/あなたは、対象のキャラクターを腐れ縁だとを感じています(または、まるで長年の腐れ縁のように気が合う相手だと感じています)。',
  63. 21..22 => '師弟/そのキャラクターとは、師弟のような関係だと感じています。',
  64. 23..24 => '好敵手/そのキャラクターを、好敵手だと感じています。',
  65. 25..26 => '親近感/あなたは、対象のキャラクターに、親近感を抱いています。',
  66. 31..32 => '友情/あなたは、対象のキャラクターに、友情を抱いています。',
  67. 33..34 => '尊敬/あなたは、対象のキャラクターを尊敬しています。',
  68. 35..36 => '庇護/あなたは、対象のキャラクターを守らなければと感じています。',
  69. 41..42 => '好感/あなたは、対象のキャラクターに好感を抱いています。',
  70. 43..44 => '興味/あなたは、対象のキャラクターに興味を抱いています。',
  71. 45..46 => '感銘/あなたは、対象のキャラクターに感銘を抱いています。',
  72. 51..52 => '畏怖/あなたは、対象のキャラクターに畏怖を抱いています。',
  73. 53..54 => '信頼/あなたは、対象のキャラクターに信頼を感じています。',
  74. 55..56 => '不信感/あなたは、対象のキャラクターに不信感を抱いています。',
  75. 61..62 => '劣等感/あなたは、対象のキャラクターの能力や容姿、実績などに対し劣等感を抱いています。',
  76. 63..64 => '後悔/あなたは対象のキャラクターを見ると、後悔の念を思い出します(かつて失った人に似ている、など)。',
  77. 65..66 => '無関心/あなたは、対象のキャラクターに対して無関心を装っています。しかし本当は無視できない存在であると感じています。',
  78. }
  79. ),
  80. "RT" => DiceTable::Table.new(
  81. "襲撃表",
  82. "1D6",
  83. [
  84. "概要:今回の事件の黒幕が放ったものか、それとも何かで恨みを買ったのか、裏社会の暗殺者たちが襲撃を仕掛けてくる。迎え撃つ必要がある。\n判定:2人で判定。【機敏(SR+1)】〔†射撃〕/【身体(SR+1)】〔†白兵〕\n全員が完全成功:敵の迎撃に成功した。襲撃者を放ってきた相手もしばらくは動けないだろう。【AP】+1。\n1人でも不完全成功:何とか敵を迎撃したが、手傷を負ってしまった。PC全員は【HP】を1d+[SR]点消費する。",
  85. "概要:あまりにも目立ちすぎたせいか、自分に目を光らせている司法組織の捜査官が追ってきた。戦うわけにもいかない。誰かが囮になってうまく逃げるしかない。\n判定:1人で判定。【身体(SR+2)】〔運動〕\n全員が完全成功:うまく追手をまくことができた。しばらくは時間を稼ぐことができるだろう。【AP】+1。\n1人でも不完全成功:何とか逃げることには成功したが、体力を使い果たした。判定を行ったPCは、[調査フェイズ]終了時まで【身体】の判定で振るダイス数-1d。",
  86. "概要:偶然、一般市民に非合法の活動をしている場面を目撃される。彼らを巻き込まないためにも、何とか誤魔化した方がいいだろう。\n判定:全員で判定。【知性(SR)】〔交渉〕\n全員が完全成功:それらしい理屈をつけて、誤魔化すことができた。機転の利いた対応に、裏社会での評価も上がる。【畏敬】+2。\n1人でも不完全成功:なんとか誤魔化せたが、相手はいまいち納得できないようだ。今後、彼らの動向にも気を配る必要があるだろう。[不完全成功]だったPCは[調査フェイズ]終了まで【知性】の判定で振るダイス数-1d。",
  87. "概要:情報を整理しようと集まった瞬間、何者かに襲撃を受ける。出自は不明だが、裏社会の存在で間違いないだろう。迎撃の必要がある。\n判定:全員で判定。【機敏(SR)】〔†射撃〕/【身体(SR)】〔†白兵〕\n全員が完全成功:鮮やかに敵を撃退してみせた。【畏敬】+2。\n1人でも不完全成功:敵を撃退できたものの、手傷を負ってしまった。[不完全成功]だったPCは[調査フェイズ]終了まで【機敏】の判定で振るダイス数-1d。",
  88. "概要:君の活躍に目をつけ、闇の組織が急な情報収集の仕事を依頼してきた。やむにやまれぬ事情があり、無視することもできない。急いで片付けた方がいいだろう。\n判定:2人で判定。【知性(SR+1)】〔コンピュータ〕/【機敏(SR+1)】〔操縦〕\n全員が完全成功:コンピュータやフットワークを活かし、情報を素早く手に入れた。闇社会からの評価も上がる。【畏敬】+2。\n1人でも不完全成功:仕事は成功させたものの、少し雑なものとなって相手を落胆させてしまう。【畏敬】-1。",
  89. "概要:カローンのことを嗅ぎ回っているマスコミに、活動現場を見られてしまった。何とか言いくるめて、対処する必要がある。\n判定:1人で判定。【知性(SR+2)】〔交渉〕\n全員が完全成功:自分たちはカローンではないと言いくるめることができた。ついでに事件捜査の時間を稼ぐための偽情報をリークすることにも成功する。【AP】+1。\n1人でも不完全成功:何とか言いくるめることができたが、激しく気力を消耗してしまう。判定を行ったPCは、【EP】-1。",
  90. ]
  91. ),
  92. }.freeze
  93. 1 register_prefix('\d+CS', TABLES.keys)
  94. end
  95. end
  96. end

lib/bcdice/game_system/Chill.rb

97.22% lines covered

90.63% branches covered

108 relevant lines. 105 lines covered and 3 lines missed.
32 total branches, 29 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Chill < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Chill'
  7. # ゲームシステム名
  8. 1 NAME = 'Chill'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ちる'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・ストライク・ランク (SRx)
  14.  "SRストライク・ランク"の形で記入します。
  15.  ストライク・ランク・チャートに従って自動でダイスロールを行い、
  16.  負傷とスタミナロスを計算します。
  17.  ダイスロールと同様に、他のプレイヤーに隠れてロールすることも可能です。
  18.  例)SR7   sr13   SR(7+4)   Ssr10
  19. INFO_MESSAGE_TEXT
  20. 1 register_prefix('SR')
  21. 1 def result_1d100(total, _dice_total, cmp_op, target)
  22. 12 then: 1 else: 11 return nil if target == '?'
  23. 11 then: 0 else: 11 return nil if cmp_op != :<=
  24. 11 then: 1 if total >= 100
  25. 1 else: 10 Result.fumble("ファンブル")
  26. 10 then: 2 elsif total > target
  27. 2 else: 8 Result.failure("失敗")
  28. 8 then: 2 elsif total >= (target * 0.9)
  29. 2 else: 6 Result.success("L成功")
  30. 6 then: 2 elsif total >= (target / 2)
  31. 2 else: 4 Result.success("M成功")
  32. 4 then: 2 elsif total >= (target / 10)
  33. 2 Result.success("H成功")
  34. else: 2 else
  35. 2 Result.critical("C成功")
  36. end
  37. end
  38. 1 def eval_game_system_specific_command(command)
  39. 191 roll_strike_rank_result(command)
  40. end
  41. 1 def roll_strike_rank_result(string)
  42. 191 debug('strike_rank begin string', string)
  43. 191 wounds = 0
  44. 191 sta_loss = 0
  45. 191 dice = ''
  46. 191 dice_add = ""
  47. 191 dice_str = ""
  48. 191 else: 191 then: 0 unless /(^|\s)[sS]?(SR|sr)(\d+)($|\s)/ =~ string
  49. debug('invalid string', string)
  50. return "1"
  51. end
  52. 191 strikeRank = Regexp.last_match(3).to_i
  53. 191 then: 171 if strikeRank < 14
  54. 171 sta_loss, dice, dice_add, dice_str = check_strike_rank(strikeRank)
  55. 171 wounds, dice_w, dice_wa, dice_ws = check_strike_rank(strikeRank - 3)
  56. 171 dice = dice + ', ' + dice_w
  57. 171 dice_add += ', ' + dice_wa
  58. 171 dice_str = dice_str + ', ' + dice_ws
  59. else: 20 else
  60. 20 sta_loss, _dice, dice_add, dice_str = check_strike_rank(13)
  61. 20 dice_list = @randomizer.roll_barabara(4, 10)
  62. 20 wounds = dice_list.sum()
  63. 20 dice_ws = dice_list.join(",")
  64. 20 dice = '5d10*3, 4d10+' + ((strikeRank - 13) * 2).to_s + 'd10'
  65. 20 dice_add += ', ' + wounds.to_s
  66. 20 dice_str = "#{dice_str}, #{dice_ws}"
  67. 20 dice_list = @randomizer.roll_barabara((strikeRank - 13) * 2, 10)
  68. 20 wounds_wk = dice_list.sum()
  69. 20 dice_ws = dice_list.join(",")
  70. 20 dice_str += "+#{dice_ws}"
  71. 20 dice_add += "+#{wounds_wk}"
  72. 20 wounds += wounds_wk
  73. end
  74. 191 output = "#{dice_str} > #{dice_add} > スタミナ損失#{sta_loss}, 負傷#{wounds}"
  75. 191 string += ':' + dice
  76. 191 then: 0 else: 191 if output.empty?
  77. return "1"
  78. end
  79. 191 output = "(#{string}) > #{output}"
  80. 191 debug('strike_rank end output', output)
  81. 191 return output
  82. end
  83. 1 def check_strike_rank(strikeRank)
  84. 362 strikeRank = strikeRank.to_i
  85. 362 dice = ''
  86. 362 dice_add = ''
  87. 362 dice_str = ''
  88. 362 damage = 0
  89. 362 then: 30 if strikeRank < 1
  90. 30 damage = 0
  91. 30 dice_str = '-'
  92. 30 dice_add = '-'
  93. 30 dice = '-'
  94. else: 332
  95. 332 then: 20 elsif strikeRank < 2
  96. 20 dice = '0or1'
  97. 20 damage = @randomizer.roll_once(2)
  98. 20 dice_str = damage.to_s
  99. 20 damage -= 1
  100. 20 else: 312 dice_add = damage.to_s
  101. 312 then: 20 elsif strikeRank < 3
  102. 20 dice = '1or2'
  103. 20 damage = @randomizer.roll_once(2)
  104. 20 dice_str = damage.to_s
  105. 20 else: 292 dice_add = damage.to_s
  106. 292 then: 20 elsif strikeRank < 4
  107. 20 dice = '1d5'
  108. 20 damage = @randomizer.roll_once(5)
  109. 20 dice_str = damage.to_s
  110. 20 else: 272 dice_add = damage.to_s
  111. 272 then: 161 elsif strikeRank < 10
  112. 161 dice = (strikeRank - 3).to_s + 'd10'
  113. 161 dice_list = @randomizer.roll_barabara(strikeRank - 3, 10)
  114. 161 damage = dice_list.sum()
  115. 161 dice_add = damage.to_s
  116. 161 else: 111 dice_str = dice_list.join(",")
  117. 111 then: 71 elsif strikeRank < 13
  118. 71 dice = (strikeRank - 6).to_s + 'd10*2'
  119. 71 dice_list = @randomizer.roll_barabara(strikeRank - 6, 10)
  120. 71 total = dice_list.sum()
  121. 71 dice_add = "#{total}*2"
  122. 71 damage = total * 2
  123. 71 dice_str = "(#{dice_list.join(',')})*2"
  124. else: 40 else
  125. 40 dice = '5d10*3'
  126. 40 dice_list = @randomizer.roll_barabara(5, 10)
  127. 40 total = dice_list.sum()
  128. 40 dice_add = "#{total}*3"
  129. 40 damage = total * 3
  130. 40 dice_str = "(#{dice_list.join(',')})*3"
  131. end
  132. 362 return damage, dice, dice_add, dice_str
  133. end
  134. end
  135. end
  136. end

lib/bcdice/game_system/Chill3.rb

100.0% lines covered

92.86% branches covered

23 relevant lines. 23 lines covered and 0 lines missed.
14 total branches, 13 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Chill3 < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Chill3'
  7. # ゲームシステム名
  8. 1 NAME = 'Chill 3rd Edition'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ちる3'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・1D100で判定時に成否、Botchを判定
  14.  例)1D100<=50
  15.    (1D100<=50) > 55 > Botch
  16. INFO_MESSAGE_TEXT
  17. 1 def result_1d100(total, dice_total, cmp_op, target)
  18. 17 then: 1 else: 16 return nil if target == '?'
  19. 16 else: 16 then: 0 return nil unless cmp_op == :<=
  20. # ゾロ目ならC-ResultかBotch
  21. 16 tens = (dice_total / 10) % 10
  22. 16 ones = dice_total % 10
  23. 16 then: 6 if tens == ones
  24. 6 then: 5 if (total > target) || (dice_total == 100) # 00は必ず失敗
  25. 5 then: 1 if target > 100 # 目標値が100を超えている場合は、00を振ってもBotchにならない
  26. 1 return Result.failure("Failure")
  27. else: 4 else
  28. 4 return Result.fumble("Botch")
  29. end
  30. else: 1 else
  31. 1 return Result.critical("Colossal Success")
  32. else: 10 end
  33. 10 then: 7 elsif (total <= target) || (dice_total == 1) # 01は必ず成功
  34. 7 then: 2 if total <= (target / 2)
  35. 2 return Result.success("High Success")
  36. else: 5 else
  37. 5 return Result.success("Low Success")
  38. end
  39. else: 3 else
  40. 3 return Result.failure("Failure")
  41. end
  42. end
  43. end
  44. end
  45. end

lib/bcdice/game_system/CodeLayerd.rb

100.0% lines covered

90.91% branches covered

54 relevant lines. 54 lines covered and 0 lines missed.
22 total branches, 20 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class CodeLayerd < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'CodeLayerd'
  7. # ゲームシステム名
  8. 1 NAME = 'コード:レイヤード'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'こおとれいやあと'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・行為判定(nCL@m[c]+x または nCL+x@m[c]) クリティカル・ファンブル判定あり
  14. (ダイス数)CL+(修正値)@(判定値)[(クリティカル値)]+(修正値2)
  15. @m,[c],+xは省略可能。(@6[1]として処理)
  16. n個のD10でmを判定値、cをクリティカル値とした行為判定を行う。
  17. nが0以下のときはクリティカルしない1CL判定を行う。(1CL[0]と同一)
  18. 例)
  19. 7CL>=5 :サイコロ7個で判定値6のロールを行い、目標値5に対して判定
  20. 4CL@7 :サイコロ4個で判定値7のロールを行い達成値を出す
  21. 4CL+2@7 または 4CL@7+2 :サイコロ4個で判定値7のロールを行い達成値を出し、修正値2を足す。
  22. 4CL[2] :サイコロ4個でクリティカル値2のロールを行う。
  23. 0CL : 1CL[0]と同じ判定
  24. デフォルトダイス:10面
  25. MESSAGETEXT
  26. 1 register_prefix('[+-]?\d*CL')
  27. 1 def initialize(command)
  28. 23 super(command)
  29. 23 @sides_implicit_d = 10
  30. end
  31. 1 def eval_game_system_specific_command(command)
  32. 21 debug('eval_game_system_specific_command command', command)
  33. 21 m = /([+-]?\d+)?CL([+-]\d+)?(@(\d))?(\[(\d+)\])?([+-]\d+)?(>=(\d+))?/i.match(command)
  34. 21 else: 21 then: 0 return nil unless m
  35. 21 base = (m[1] || 1).to_i
  36. 21 modifier1 = m[2].to_i
  37. 21 target = (m[4] || 6).to_i
  38. 21 critical_target = (m[6] || 1).to_i
  39. 21 modifier2 = m[7].to_i
  40. 21 then: 12 else: 9 diff = m[9].to_i if m[9]
  41. 21 check_roll(command, base, target, critical_target, diff, modifier1 + modifier2)
  42. end
  43. 1 def check_roll(command, base, target, critical_target, diff, modifier)
  44. 21 then: 2 else: 19 if base <= 0 # クリティカルしない1D
  45. 2 critical_target = 0
  46. 2 base = 1
  47. end
  48. 21 result = Result.new
  49. 21 then: 0 else: 21 target = 10 if target > 10
  50. 21 dice_list = @randomizer.roll_barabara(base, 10).sort
  51. 135 success_count = dice_list.count { |x| x <= target }
  52. 135 critical_count = dice_list.count { |x| x <= critical_target }
  53. 21 result.critical = critical_count > 0
  54. 21 success_total = success_count + critical_count + modifier
  55. 21 mod_text = Format.modifier(modifier)
  56. # (10d10+5)
  57. 21 text = "#{command} > (#{base}d10#{mod_text}) > [#{dice_list.join(',')}]#{mod_text} > "
  58. 21 else: 17 then: 4 text += "判定値[#{target}] " unless target == 6
  59. 21 else: 17 then: 4 text += "クリティカル値[#{critical_target}] " unless critical_target == 1
  60. 21 text += "達成値[#{success_count}]"
  61. 21 then: 5 else: 16 if success_count <= 0
  62. 5 result.fumble = true
  63. 5 result.failure = true
  64. 5 result.text = "#{text} > ファンブル!"
  65. 5 return result
  66. end
  67. 16 then: 4 else: 12 text += "+クリティカル[#{critical_count}]" if result.critical?
  68. 16 text += mod_text
  69. 16 then: 11 else: 5 text += "=[#{success_total}]" if result.critical? || modifier != 0
  70. 16 then: 7 if diff.nil?
  71. 7 else: 9 result.text = "#{text} > #{success_total}"
  72. 9 then: 7 elsif success_total >= diff
  73. 7 result.text = "#{text} > 成功"
  74. 7 result.success = true
  75. else: 2 else
  76. 2 result.text = "#{text} > 失敗"
  77. 2 result.failure = true
  78. end
  79. 16 return result
  80. end
  81. end
  82. end
  83. end

lib/bcdice/game_system/ColossalHunter.rb

99.03% lines covered

84.38% branches covered

103 relevant lines. 102 lines covered and 1 lines missed.
32 total branches, 27 branches covered and 5 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/format"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class ColossalHunter < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'ColossalHunter'
  8. # ゲームシステム名
  9. 1 NAME = 'コロッサルハンター'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'ころつさるはんたあ'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~MESSAGETEXT
  14. ・判定(nCH±x>=y)
  15.  nD6の判定。クリティカル、ファンブルの自動判定を行います。
  16.  n:ダイス数。省略可能。省略した場合3。
  17.  x:修正値。省略可能。
  18.  y:目標値。省略可能。
  19.  例) CH CH+1 CH+2>=10 4CH+1
  20. ・BIG-6表(B6T)
  21. ・覚醒表(AWT)
  22. ・現状表(CST)
  23. ・ハンターマーク表(HMT)
  24. ・特徴表(SPT)
  25. ・プレシャス表(PRT)
  26. ・専門能力表(EXT)
  27. ・コロッサル行動表(CAT)
  28. ・NPC作成表(CNP)
  29. ・D66ダイスあり
  30. MESSAGETEXT
  31. 1 def initialize(command)
  32. 72 super(command)
  33. 72 @d66_sort_type = D66SortType::NO_SORT
  34. end
  35. 1 def eval_game_system_specific_command(command)
  36. 72 getCheckRollDiceCommandResult(command) ||
  37. getSourceSceneDiceCommandResult(command) ||
  38. getCreateNpcDiceCommandResult(command) ||
  39. getTableDiceCommandResult(command)
  40. end
  41. 1 def getCheckRollDiceCommandResult(command)
  42. 72 debug("getCheckRollDiceCommandResult command", command)
  43. 72 parser = Command::Parser.new(/\d*CH/, round_type: round_type)
  44. .restrict_cmp_op_to(nil, :>=)
  45. 72 parsed = parser.parse(command)
  46. 72 else: 14 then: 58 unless parsed
  47. 58 return nil
  48. end
  49. 14 else: 1 then: 13 parsed.command = "3CH" unless parsed.command.start_with?(/\d/)
  50. 14 dice_count = parsed.command.to_i
  51. 14 modify = parsed.modify_number
  52. # ダイスロール
  53. 14 dice_list = @randomizer.roll_barabara(dice_count, 6)
  54. 14 dice = dice_list.sum()
  55. 14 dice_str = dice_list.join(",")
  56. 14 total = dice + modify
  57. # 出力文の生成
  58. 14 text = "(#{parsed}) > #{dice}[#{dice_str}]#{Format.modifier(modify)} > #{total}"
  59. 14 result = get_judge_result(dice, total, parsed)
  60. 14 result.text = text + result.text
  61. 14 return result
  62. end
  63. # 成否判定
  64. 1 def get_judge_result(dice, total, parsed)
  65. 14 then: 6 if dice <= 5
  66. 6 else: 8 Result.fumble(" > ファンブル")
  67. 8 then: 4 elsif total >= 16
  68. 4 else: 4 Result.critical(" > クリティカル")
  69. 4 then: 2 elsif parsed.cmp_op.nil?
  70. 2 else: 2 Result.new("")
  71. 2 then: 1 elsif total >= parsed.target_number
  72. 1 Result.success(" > 成功")
  73. else: 1 else
  74. 1 Result.failure(" > 失敗")
  75. end
  76. end
  77. 1 def getSourceSceneDiceCommandResult(command)
  78. 58 else: 36 then: 22 return nil unless command =~ /^B6T$/
  79. 36 name = "BIG-6表"
  80. 36 table = getBig6Table
  81. 36 yearTitle = "年齢"
  82. 36 return getYearTableResult(name, table, yearTitle)
  83. end
  84. 1 def getYearTableResult(name, table, yearTitle)
  85. 36 item, index = get_table_by_d66(table)
  86. 36 then: 0 else: 36 return nil if item.nil?
  87. 36 title, text, yearText, = item
  88. 36 debug('yearText', yearText)
  89. 36 year, calculateText = getYear(yearText)
  90. 36 result = "#{name}(#{index}) > #{title}:#{text} > #{yearTitle}:#{yearText}"
  91. 36 else: 12 then: 24 result += " > #{calculateText} > #{yearTitle}:#{year}" unless year.nil?
  92. 36 result += "歳"
  93. 36 return result
  94. end
  95. 1 def getYear(yearText)
  96. 60 text = yearText.gsub(/(\d+)D(6+)/) { getD6xResult(Regexp.last_match(1).to_i, Regexp.last_match(2).length) }
  97. 36 else: 25 then: 11 unless text.match?(%r{^[+\-*/\d]+$})
  98. 11 return nil
  99. end
  100. 25 then: 1 else: 24 if text.match?(/^\d+$/)
  101. 1 return nil
  102. end
  103. 24 year = ArithmeticEvaluator.eval(text)
  104. 24 return year, "(#{text})"
  105. end
  106. 1 def getD6xResult(count, dice6Count)
  107. 24 total = 0
  108. 24 count.times do |_i|
  109. 49 number = 0
  110. 49 dice6Count.times do |_i|
  111. 49 number *= 10
  112. 49 dice = @randomizer.roll_once(6)
  113. 49 number += dice
  114. end
  115. 49 total += number
  116. end
  117. 24 return total.to_s
  118. end
  119. 1 def getBig6Table
  120. table =
  121. [
  122. 36 ["この世の地獄", "あれはまさに地獄。屍の山。嘆く者。呆然とする者。目の前で潰される者。あの日、人類は霊長ではなく……弱き獣の一種となった。", "15+2D6"],
  123. ["悪の時代", "全ての崩壊、呆然の時。救援が望めぬとわかったなら、少なからぬ者が悪に走った。あの頃は、あなたもまた下劣なる略奪者だった。", "18+2D6"],
  124. ["消えざる罪", "混乱の中、あなたは……私怨を晴らした。許せない人間を、その手で始末した。罪に問う者はいない……他ならぬあなた自身以外は。", "18+2D6"],
  125. ["言葉にできない", "ただ呆然と。廃人のようにあの期間を過ごした。目の前で何が起きていたかは覚えているけれど。思い出したくは……ない。", "任意(最低14)"],
  126. ["望む時代", "あの平和で膿んだ世界が嫌いだった。全てが壊れて、訪れた無法の時代。あなたは、あの日常が壊れた今を歓迎している。", "18+2D6"],
  127. ["あなたの呪い", "世界を怨み、自殺しようとした時、世界は変わった。あなたの呪詛が形になったように……コロッサルが全てを破壊し始めたのだ。", "任意(最低20)"],
  128. ["肉親の命日", "家族は、あなたの全てだった。だからあの日は、全てが失われた日だ。注ぐ愛も注がれる愛も、きっとあの日に枯れたのだ。", "任意(最低14)"],
  129. ["戦友の命日", "あなたとその仲間は無抵抗をよしとせず、コロッサルに立ち向かった。そして……あなた以外は全員が死んだ。彼らの分も生きなければ。", "30+3D6"],
  130. ["トラウマ", "あの日を思い出すだけで、震えが止まらず汗と涙が溢れ出す。忘れるためには、コロッサルと戦い続けるしかないだろう、きっと。", "任意(最低14)"],
  131. ["死を逃した時", "意識を失い、目覚めれば全ては壊れた後。生き延びたのは幸運なのか。不幸なのか。あるいはそれとも、呪いなのか。", "10+3D6"],
  132. ["呪縛", "あの時、無数の死を見た。その中で、ある一人が言った言葉が忘れられない。それは今も、あなたを縛る呪いとなっている。", "18+2D6"],
  133. ["ひっかかり", "あの日、配偶者あるいは恋人と別れた。恋の終わりと、世界の終わり。あれ以来、相手が生きているかもわからない……。", "25+3D6"],
  134. ["重症", "昏睡BIG-6で重い疵を負ったあなたは、長く昏睡状態だった。幸いにも人工冬眠装置によって、あなたは年を経ずに目を覚ましたが……。", "任意"],
  135. ["些末事", "あなたにはコロッサルの出現などよりも重要な目的がある。BIG-6など、どうでもよい。あなたは決して揺らぎはしないのだ。", "任意"],
  136. ["財産の消滅", "築き上げていた全てが失われた日。あなたにとって全てだった財貨も、権力も、消滅したあの日を、どうして忘れられようか。", "35+3D6"],
  137. ["告白未遂", "告白しようとしていたその日、コロッサルが現れた。崩れる日常。あの人が生きているのか、どうなったのか、何もわからない。", "18+2D6"],
  138. ["記憶喪失", "あの時、何があったのか、どうしても思い出せない。何か重大なことがあったはずなのに……思い出そうとすると頭痛が襲うのだ。", "任意(最低14)"],
  139. ["誕生の時", "BIG-6と同年、コロッサル襲撃の最中に生まれ、赤ん坊の状態で生存者らに保護された。親はわからない。あなたの生存は奇跡である。", "10"],
  140. ["ルーツ", "コロッサルによって破壊された瓦礫の合間に残されていた子……それがあなただ。親という概念すらなく、あなたは育ってきた。", "8+1D6"],
  141. ["伝え聞くのみ", "物心ついた時には周囲はコロッサルの脅威にさらされていた。BIG-6以前については何も知らない。遥か過去のようにすら思えている。", "8+1D6"],
  142. ["語られざること", "ZOSで育ったあなたには誰もBIG-6について教えてくれなかった。大人の会話の合間から、なんとなく想像するだけだ。", "8+1D6"],
  143. ["絵物語", "瓦礫でない建物。人が街にあふれかえる。なんという子供だましのおとぎ話だろう。あなたはBIG-6以前の存在を信じていない。", "8+1D6"],
  144. ["何それ", "隊商に見つけられるまで、獣同然に生きていた。BIG-6などあったことも知らない。物心ついた時には、餌を求め走っていたのだ。", "9+1D6"],
  145. ["嫉妬", "BIG-6時をあなたは覚えていない。そして、BIG-6以前の豊かさと平和に激しい嫉妬を抱き、守れなかった大人たちを恨む。", "9+1D6"],
  146. ["忘れたい記憶", "あなたはあの日を忘れようと努めた。今ではほとんど忘れたと言っていい。けれど、ふとした時にあの地獄の光景は現れて……。", "任意(最低14)"],
  147. ["始まりの時", "あなたにとってあれは終わりではなく、始まり。停滞して行き詰まった世界が動き出し、どうでもよかった己の命を感じさせてくれた瞬間。", "15+3D6"],
  148. ["かすかな記憶", "当時のあなたは幼かった。それでもうっすらと、あの平和で豊かだった時代を覚えている。いっそ知らなければ……と思うのだけれど。", "10+1D6"],
  149. ["崩壊と再生", "あなたの人生は、BIG-6による社会崩壊と……その後の再生をなぞるものだ。あなたはBIG-6以後を何より間近で見て来た。", "10+1D6"],
  150. ["他人事", "とても辺鄙な地方にいたせいか、コロッサルは出現しなかった。無論、影響はあったが……ゆっくりとしたもので。大災害の印象は薄い。", "6+3D6"],
  151. ["新たな時代", "まだマテリアルの価値が定かでなかった頃から、あなたはその価値に目を付けていた。応用法も含め……社会崩壊後に備えたのだ。", "任意(最低17)"],
  152. ["動乱", "当時は現役かつ、責任ある立場だった。守るために、あなたは全力で戦い、逃げ……そして時には同じ人間からも奪った。", "40+4D6"],
  153. ["自信の元", "あなたは一家の長として家族を守り、導いた。全てが破壊される中、家族は確かに生き延びて、あなた自身も未だ生き残れたのだ。", "35+3D6"],
  154. ["本能的記憶", "気が付けばゾーンに“いた”。コロッサルはさまざまな生物をクラフトする。中には小型のコロッサルとして独立して活動を開始するものもいるという。あなたもまた、気づいてほどなくハンターとして目覚めた。そう……あなたはクラフトされた存在。人よりもコロッサルに近い存在。記憶も感情も、どこまでが己のものなのか……。これは、およそ知られていい秘密ではない。(注意:外見年齢は任意)", "2D6-2"],
  155. ["体験無き事象", "あなたは母から生まれた人間ではなく、人工的なハンター作成の副産物たるクローニング技術の結晶だ。親は知らないが“作者”は知っている。肌にはバーコードが刻まれ、その体が通常の人間ではないと思い知らされるだろう。丁寧に記憶まで、一定量が流し込まれており、日常生活には支障がない。この出生は隠さねばならない。(注意:外見年齢は任意。覚醒表の内容は作られた記憶である)", "2D6-2"],
  156. ["特異点", "あのBIG-6の中では奇妙な時空のねじれが発生した。そして、あなたのようにありえざる時代や世界から、迷い込む者も現れたのだ。この事実は隠さねばならない……が、教えても誰も本気にはしないだろう。なお、あなたがどれほど特殊な能力や知識を持っていたとしても、データ上において他のPCと何ら変わらない。演出において、他の時代や異世界の知識や技術をいくらか使える程度である。", "任意(最低10)"],
  157. ["覚醒の時", "BIG-6時に絶望の中でコロッサルに抗い、生まれた第一世代のハンター。平和の時代を知る存在。そして平和を壊され、平和を取り戻さんと渇望する存在だ。ハンターの中でも、最初期であり最も経験豊富であり、同じハンターらからは敬意を捧げられる。もちろん、相応の振る舞いも求められるだろうが……。(注意:覚醒表における「ZOS」は、「故郷」か「組織」に変わる)", "任意(最低17)"],
  158. ]
  159. 36 return table
  160. end
  161. 1 def getCreateNpcDiceCommandResult(command)
  162. 22 else: 2 then: 20 return nil unless command =~ /^CNP$/
  163. 2 name = "NPC作成表"
  164. table = [
  165. 2 ['ハンター嫌いの', 'ごろつき', '全てへの絶望'],
  166. ['心に傷を負った', '罪人', 'あなたへの殺意'],
  167. ['精神不安定な', '浮浪者', 'ハンターへの殺意'],
  168. ['病に伏した', '盗人', '己自身への殺意'],
  169. ['重傷を負った', '終末論者', 'ハンターへの憎悪'],
  170. ['悪名高い', '旅人', 'コロッサルへの崇拝'],
  171. ['横暴な', '難民', '人間への嫌悪'],
  172. ['あなたに依存している', '子供', 'あなたへの恐怖'],
  173. ['無謀な', '老人', '左隣PCへの殺意'],
  174. ['乱暴な', '少年', '窃盗への依存'],
  175. ['信用できない', '少女', '快楽への依存'],
  176. ['臆病な', '若者', '愛情への依存'],
  177. ['だらしない', '芸人', '未来への絶望'],
  178. ['短絡的な', '娼婦/男娼', '弱者への蔑視'],
  179. ['怠け者の', '元軍人', '己自身への嫌悪'],
  180. ['享楽的な', 'ハンター志願者', 'あなたへの疑念'],
  181. ['エキセントリックな', '元ハンター', 'ギャンブルへの依存'],
  182. ['ずる賢い', '労働者', 'アルコールへの依存'],
  183. ['恋人のいる', 'スカベンジャー', '孤独への恐怖'],
  184. ['残念な', '仕立て屋', 'ハンターへの恐怖'],
  185. ['空回りしている', '職人', 'コロッサルへの憎悪'],
  186. ['酒びたりの', '教師', 'ハンターへの不安'],
  187. ['妄想癖のある', '建築家', 'ハンターへの嫉妬'],
  188. ['努力家の', '商人', 'コロッサルへの恐怖'],
  189. ['やさしい', '料理人', '己の命への執着'],
  190. ['神秘的な', '漁師/猟師', 'あなたへの打算'],
  191. ['世馴れた', '農家', '過去への執着'],
  192. ['信用できる', '自警団員', 'マテリアルへの執着'],
  193. ['達観した', '看護師', 'ハンターへの憧憬'],
  194. ['血気盛んな', '研究者', 'あなたへの嫉妬'],
  195. ['美貌の', '技師', '異性への執着'],
  196. ['気高い', '医師', '力への渇望'],
  197. ['優秀な', '神父/シスター', 'ZOSへの依存'],
  198. ['天才肌の', '事務屋', '左隣PCへの執着'],
  199. ['誰からも愛される', '指導者', 'あなたへの羨望'],
  200. ['あなたに恋をしている', 'ハンター', 'あなたへの執着'],
  201. ]
  202. 2 nature, nature_number = getD66Item(table, 0)
  203. 2 type, type_number = getD66Item(table, 1)
  204. 2 secret, secret_number = getD66Item(table, 2)
  205. 2 result = "#{name}(#{nature_number}, #{type_number}, #{secret_number}) > 性質:#{nature}/タイプ:#{type}/心の秘密:#{secret}"
  206. 2 return result
  207. end
  208. 1 def getD66Item(table, index)
  209. 6 item, number = get_table_by_d66(table)
  210. 6 return item[index], number
  211. end
  212. 1 def getTableDiceCommandResult(command)
  213. 20 info = TABLES[command]
  214. 20 then: 0 else: 20 return nil if info.nil?
  215. 20 name = info[:name]
  216. 20 type = info[:type]
  217. 20 table = info[:table]
  218. text, number =
  219. 20 else: 0 case type
  220. when: 0 when '2D6'
  221. get_table_by_2d6(table)
  222. when: 2 when '1D6'
  223. 2 get_table_by_1d6(table)
  224. when: 18 when 'D66'
  225. 18 get_table_by_d66(table)
  226. end
  227. 20 then: 0 else: 20 return nil if text.nil?
  228. 20 return "#{name}(#{number}) > #{text}"
  229. end
  230. TABLES =
  231. {
  232. 1 'AWT' => {
  233. name: "覚醒表",
  234. type: 'D66',
  235. table: [
  236. '実験体:当時ハンターを人工的に作り出すべく、倫理を無視した研究が多数行われていた。あなたこそ、無数の犠牲の上に生まれた……数少ない成功作なのだ。',
  237. 'ゾーン留置刑:刑罰としてコロッサルの進路に拘束され放置される罪人がいる。多くは命を落とすが、ハンターとして目覚める可能性もあるのだ。他ならぬあなたのように……。',
  238. 'ハンター殺し:相応の理由はあったから。頭部への一撃で、非道のハンターを殺してやった。その報いか。その瞬間、あなた自身がハンターになってしまったのだ。',
  239. '目の前の変異:死んだハンターのコアが目の前でコロッサルと化す。しかし何という皮肉か。発生したゾーン。まき散らされるマテリアル。あなたはハンターとして覚醒した。',
  240. 'ZOS壊滅:住んでいたZOSがコロッサルに蹂躙される。全てが破壊され、大切なものは全て失われる。無力感の中……皮肉にも、あなたは新たな力に目覚めた。',
  241. '生贄:ハンターのいない集団は時として奇妙な行為をする。弱者を生贄に捧げるのだ。それは、あなたというハンターを生み出し……集団はコロッサルに滅ぼされた。',
  242. '崩壊と追跡:ZOSの崩壊。誰も生き残らず。あなたは一人、復讐者と化して旅立つ。決意と覚悟が、あなたにハンターの力を与えてくれた。これは復讐の刃なのだ。',
  243. '臨死経験:コロッサルの一撃であなたは死んだ……だが、唯一無事だった脳がコアと化し、肉体を再構築し……あなたは再び立ち上がったのだ。',
  244. '脱走:実験施設か牢獄か、あるいは監禁場所か。あなたは死に物狂いで逃げ出した。偶然ゾーンに入っていたのか。あなたはハンターとなり、無事逃げ延びた。',
  245. '感情の暴発:それは狂気だったのかもしれない。あなたはその時、抑えきれぬ感情を爆発させ、ありえぬ行動を、ありえぬように行った。ハンターとして覚醒したのだ。',
  246. '肉体の欠損:まともな医療がないこの時代。体の一部を失う者は多い。あなたは絶望に呑まれず、失った体を、意志の力でクラフトした。そう、ハンターになったのだ。',
  247. '飢餓:荒野で飢え、渇き、あがいた。誰にも助けてもらえない中……幸運にもそのゾーンであなたは力に目覚める。鳥や獣を捕らえ貪り、生き延びたのだ。',
  248. '過剰な復讐:憎悪を募らせ、あなたは後先を考えず怨念の一撃を繰り出す。いつの間にか手には強大な武器があり、相手は建物ごと破壊された。憎悪に満ちた覚醒。',
  249. '遅すぎた覚醒:大切な人が死ぬ。故郷が破壊される。全てを失い、絶望に打ちひしがれながら、仇たるコロッサルの遥か背後で、ハンターとして覚醒した。何もかも手遅れなのに。',
  250. '贖罪の印:大切な人をあなた自身の手で殺してしまった。後悔と絶望の中、あなたはなぜかハンターとなる。それは己の贖罪のために与えられた力と思えた。',
  251. '瓦礫の闇:瓦礫の中、身動きは取れない。誰も助けてくれない。閉塞感と飢餓感と絶望、理不尽への怒り。最後まで足掻きに足掻いてハンターとして目覚め、脱出した。',
  252. '無謀なる突撃:ただ許せなかったのだ。故郷を蹂躙するコロッサルへ、武器とも呼べぬものを手に突撃する。ハンターとしての覚醒は、幸運の結果だったのだろう。',
  253. '残された遺志:コロッサルの襲撃の中、一人のハンターがあなたを守り……命を落とした。その後の残ったマテリアルに触れた瞬間、あなたはハンターとして覚醒したのだ。',
  254. '危機的覚醒:迫り来るコロッサルの一撃。けれど死を覚悟した瞬間、自身でも信じられない動きで攻撃を回避していた。そう、あなたはハンターになったのだ。',
  255. '猛る夜:その夜、あなたは恐怖と不安の中で、湧き上がる欲望のまま獣となって猛り、貪った。その欲望の一夜を経て、あなたは人を超えてハンターへと変わる。',
  256. 'コロッサル接触:瀕死のあなたに、コロッサルが触れる。その瞬間、あなたはハンターとなり生き延びた。あのコロッサルはなぜ、人を救うようなことをしたのだろう?',
  257. '記憶喪失:何か大きな出来事があったはずなのだ。けれど思い出せない……いったいどうして、あなたがハンターとなったのか。かつて何があったのか、あなたは知りたい。',
  258. '偶然の獲得:ちっぽけな反抗、隔意、逃避。あなたはその日、ZOSを飛び出しコロッサルの領域内に立ち入ってしまい、偶然、ハンターとして目覚め、無事に生還した。',
  259. 'ゾーン研究:あなたは学術的な興味から、ハンターに守られ何度もゾーンに入った。そして気づけば、あなた自身がハンターの力を得ていたのだ。',
  260. 'ハンター志願:希望のない世界で、希望を得るため。多くは生きて帰れぬことを知りながら、コロッサルに立ち向かった。幸運にも……あなたはハンターとして覚醒できた。',
  261. '野生の日々:集団に属せず、あなたは半ば野生の中で一人生き延びていた。コロッサルにも狙われず、ゾーンで共存すらした。ハンターの力を得たのも必然だろう。',
  262. '自由落下:の中でふとした事故で、あなたは高所から落下した。けれど落下中、足場をクラフトし、あなたは九死に一生を得た。ハンターとして覚醒したのだ!',
  263. '昏睡:重傷を負って昏睡に陥り、夢の中で地の底からの囁きを聞いた。そして目覚めた時、あなたは能力にも目覚め、ハンターとなっていたのだ。',
  264. '極限の修練:愚直に信じて、信じて、信じて、嘲笑われても修練を繰り返した。努力の価値はわからない。それでもあなたは、己の覚醒を修練の結果だと信じている。',
  265. 'ハンターとの恋:あなたの恋人はハンターだ。あるいは、ハンターだった。その交わりの中で、恋人のゾーンに深く影響され……気づけばハンターの能力を得ていた。',
  266. '恩人の危機:ZOSを守って来たハンター。逃げ遅れたあなた。目の前でハンターがコロッサルの一撃を受けて散ろうとするその瞬間……あなた自身が力に目覚めた。',
  267. '守る力:大切な人を守るため、迫り来るコロッサルの前であなたは目覚めた。新たな力は、コロッサルを倒し……あなたは無事に、守るべき人を守り切ったのだ。',
  268. '蟷螂の斧:たとえ無意味でも無価値でも、反抗の意を見せずにいられないから、あなたはコロッサルに立ち向かった。そして、己が無力ではないと、証明したのだ。',
  269. 'ガイアの声:地の底から、呼びかける声を聞いた。コロッサルの傍にいたわけではない。しかし、その声を聞いた瞬間、あなたはハンターとなった。なってしまったのだ。',
  270. '天性のハンター:初めてコロッサルに対峙した時、自然にリクラフトして武装していた。しかも、歴戦のハンターと同等以上の巧みさで。あなたはこの時代、待望された天才だ。',
  271. 'ありえぬ存在:BIG-6以前から、あるいはものごころつく以前から、ハンターの能力が開花していた。周囲の目は期待と不安、そして打算にまみれている。'
  272. ],
  273. },
  274. 'CST' => {
  275. name: "現状表",
  276. type: 'D66',
  277. table: [
  278. '逃れえぬ恐怖:かつての悪夢は心を握りしめ、離してはくれない。平時は暗がりの隅で一人震え、ぶつぶつと呟くばかり。友らは、立ち直らせようとしてくれているが……。 リーダー度:2',
  279. '人間証明:いつからか自傷癖が身についてしまった。己が人間だと証明したいから。流れる血が赤いと知りたくて。己の手首を何度も何度も切り刻んでしまうのだ。 リーダー度:3',
  280. '裏切者:かつて、あなたはコロッサルと戦う仲間を見捨てて逃げ出した。連携は崩れ、多くの仲間が散った。以来、あなたを信用する者はいない。いるわけがない。 リーダー度:1',
  281. '人間不信:あなたは人々に裏切られ、罵られ、追放された身。ハンター同士ならまだしも、もはや人は信じられない。コロッサル以上に人間がおぞましいのだ。 リーダー度:2',
  282. '孤独:力を得れば、周囲は距離を取る。それがつらくて……逃げてしまった。もう人には関わらない。今や誰も近づいては来ない。あなたは独りぼっちなのだ。 リーダー度:2',
  283. '無法の首魁:力を得て増長したあなたには、多数の取り巻きがいる。暴虐も我儘も、ある程度は許されるのがハンターだ。今のあなたは、無法者の首領も同然である。 リーダー度:9',
  284. '生存者:何も守れず……あなたのZOSはコロッサルに破壊された。ただ一人……ハンターの力で生き延びたのだ。今はただ前へ足を進めるだけで精一杯。 リーダー度:3',
  285. '検体:乞われて研究者の検体に立候補した。あなたには何もない。どうされてもいい。力が手に入るならよし。誰かの礎になるならそれも……よし。 リーダー度:5',
  286. '刹那の快楽:何度出撃しようとも、コロッサルは恐ろしい。生きて戻ってくれば、次の出撃を恐れる。あなたは酒色に溺れ、現実から少しでも逃れようともがくだろう。 リーダー度:3',
  287. '戦闘機械:戦う以外は考えられなくなってしまった。何をすればいいのかわからないのだ。ただぼんやりと空を眺めているしか……することがない。 リーダー度:5',
  288. '亡霊を背負う:毎日、散っていった者たちの姿が脳裏に浮かぶ。彼らはあなたに力をくれるのだろうか。それとも、あなたを彼らと同じ場所へ導こうとしているのだろうか。 リーダー度:8',
  289. '雇用契約:大切な人を保護してもらう代わり、あなたはZOSのハンターになった。その人にはなかなか会えないけれど。きっと満足な生活を送っている……はずだ。 リーダー度:7',
  290. '鍛錬の日々:共にハンターとして組んで来た戦友がいた。今はもう全て土の下だ。彼らの分まで戦わねばならない。幸せになってはいけない。己の修練が全てだ。 リーダー度:9',
  291. '悪党の末路:悪事を重ね、ZOSを追放された。根無し草となり放浪する中、あなたの性根も少しは正されたろうか? それとも逆恨みの炎は消えていないのか? リーダー度:1',
  292. 'ワーカホリック:恐怖があなたを働かせる。どんな雑務でもいいから仕事が必要だ。楽しみを知らないわけではないが……働いていないと、背後にまた恐怖が迫ってくる。 リーダー度:10',
  293. '虚ろな愛:恋人ないし配偶者がいる。しかし関係はもはや形だけ。その心はあなたに向いていない。心を向ける相手は別にいるのだ……しかし、それでも、あなたは。 リーダー度:6',
  294. '餓えしもの:今の世の中、マテリアルが金だ。コロッサルと戦えば戦うほど、あなたは財力と権力を得る。あなたは力に餓えて餓えて、戦いにも餓えているのだ。 リーダー度:8',
  295. '家族を背負い:病か老いか、あるいは重傷を負ってまともに働けない家族がいる。家族を養い、RIACTの保護を受けるためにも、あなたは働かねばならない。 リーダー度:7',
  296. '多情:こんな世の中では人の命は儚く、人の心もまた儚い。だからあなたは、いつも恋をして、いつも愛を囁いて。せめて己の軌跡を多くの人に残そうとする。 リーダー度:5',
  297. '人捜しの旅:かつて生き別れた大切な人を捜して、ZOSからZOSへと渡り歩いている。きっと、必ず、どこかで生き延びている……はずだ。 リーダー度:1',
  298. '善き狩人:特に働くわけではないが……あなたが披露する武勇伝は新世代を鼓舞し、ハンターへの憧れを抱かせる。人はコロッサルを恐れてばかりでは前に進めない。 リーダー度:8',
  299. 'カジノ:ハンターならざる人々も、刹那的な享楽で全てを忘れようとしている。あなたは小さなカジノを営み、人々を楽しませる一方で、己の懐をあたためている。 リーダー度:4',
  300. '恋々的日々:あなたは恋人のためハンターとして活躍する。恋の中で日々は輝き、全ての悪夢はかき消される。今のあなたは、幸福な夢にどこまでも盲目でいられる。 リーダー度:9',
  301. '語り手:現実は、つらい。今の世には逃避する先が必要なのだ。だからはあなたは物語を読み漁り、時には自ら物語を書き、また時にはTRPGをする。 リーダー度:4',
  302. 'スカベンジャー:崩壊した世界には隠されし謎・宝が無数にある。あなたは日々、廃墟を漁って機材や情報媒体を拾い集める。それは確かなZOSへの貢献となるのだ。 リーダー度:7',
  303. 'エンジニア:機械いじりは楽しい。かつてあった文明の遺産から、新たなものを生み出す時、あなたは人類の前に広がる、明るい未来を信じられるのだ。 リーダー度:6',
  304. '医師:既に人と言えないハンターの体。しかし、それでも自らが何度も壊れ、再構成してきたからこそ……人の体を知る。平時のあなたは、ZOSの医師だ。 リーダー度:10',
  305. '訓練教官:最低限の自衛を覚えてもらうため。コロッサルについて若者らに教え、緊急時の対応を訓練する。その中にハンターとなる者もいるのだろうか? リーダー度:12',
  306. '農家:コロッサルとの戦闘で少なからぬ人々が死ぬ。新たな命を芽生えさせ生かすべく……あなたは平時、農業に精を出している。農地と実りはあなたの宝だ。 リーダー度:11',
  307. '一家の主:恋人ないし配偶者がいる。もうすぐ家族は増えそうだ。未来は明るい。だから出撃したなら……きっと生きて、帰らねばならない。 リーダー度:10',
  308. 'トレーダー:あなたはハンターである以上に商人だ。自らZOSからZOSへ商品を運び、マテリアルを獲得する。マテリアルの貯蓄が、今のあなたの生き甲斐だ。 リーダー度:4',
  309. 'アイドル:荒廃した世界だからこそ、人には娯楽が必要だ。あなたは自らの歌や踊りで人々を鼓舞し、その心に輝きを取り戻さんとする。未来はきっと、明るいはずだ。 リーダー度:6',
  310. '自警団長:ZOSの治安はよくない。人々は皆、自暴自棄だ。ハンターにも不埒の輩は多い。あなたは人が人らしくあるべく、自警団を組織している。 リーダー度:12',
  311. '孤児院長:偽善と知りつつ、あなたは多数の孤児らを集め育てている。彼らを受け入れ、育てられるのはマテリアルを直接獲得してくるハンターくらいなのだ。 リーダー度:11',
  312. '導き手:自身も葛藤しつつ、あなたは宗教者として人に教えを説く。神に見放されたこの世界でも、心の支えは必要だ。人の心は救われねばならない。 リーダー度:11',
  313. '指導者:あなたはZOSの顔役だ。多くの人望を集め、ハンターの地位を向上させている。一挙一動が注目を受ける。気をひきしめて日々を過ごさねば。 リーダー度:12'
  314. ],
  315. },
  316. 'HMT' => {
  317. name: "ハンターマーク表",
  318. type: 'D66',
  319. table: [
  320. '顔',
  321. '胸',
  322. '背中',
  323. '胴',
  324. '肩',
  325. '腕',
  326. '顔',
  327. '胸',
  328. '背中',
  329. '胴',
  330. '肩',
  331. '腕',
  332. '顔',
  333. '胸',
  334. '背中',
  335. '胴',
  336. '肩',
  337. '腕',
  338. '掌',
  339. '腿',
  340. '脛',
  341. '足裏',
  342. '全身',
  343. '片眼',
  344. '掌',
  345. '腿',
  346. '脛',
  347. '足裏',
  348. '全身',
  349. '片眼',
  350. '掌',
  351. '腿',
  352. '脛',
  353. '足裏',
  354. '全身',
  355. '片眼'
  356. ],
  357. },
  358. 'SPT' => {
  359. name: "特徴表",
  360. type: 'D66',
  361. table: [
  362. '死んだ魚の目',
  363. '凶悪な容貌',
  364. '子供のように小柄',
  365. '目の下の隈',
  366. '疲れ切った背中',
  367. '威圧的な筋肉',
  368. 'ガリガリの痩身cc',
  369. '中性的な顔立ち',
  370. '無数の傷痕',
  371. '顔に残る傷痕',
  372. '隻眼',
  373. '男装・女装',
  374. '樽のような肥満',
  375. '目立つ犬歯',
  376. 'ぎらつく眼光',
  377. '奇妙なタトゥー',
  378. '見上げるような長身',
  379. '泣きボクロ',
  380. '滑らかな髪',
  381. '手入れされた髪型',
  382. '腰まで届くロングヘア',
  383. 'ベリーショート',
  384. 'ドレッド',
  385. 'スキンヘッド',
  386. '特殊な形の瞳',
  387. '三白眼',
  388. 'オッドアイ',
  389. '糸目',
  390. '眼鏡',
  391. '冷たい眼差し',
  392. 'きれいな指',
  393. 'すべやかな肌',
  394. '優しげな声',
  395. '明るい笑顔',
  396. '健康的な体',
  397. '整った容貌'
  398. ],
  399. },
  400. 'PRT' => {
  401. name: "プレシャス表",
  402. type: 'D66',
  403. table: [
  404. '壊れたスマートフォン',
  405. '誰かの写真',
  406. '鳴らないヘッドホン',
  407. '記念の指輪',
  408. '血まみれの布',
  409. '空のスキットル(酒用の水筒)',
  410. '錆びたナイフ',
  411. '骨の欠片',
  412. '古い銃と弾丸1発',
  413. '銀の十字架',
  414. '謎の携帯メモリ',
  415. 'インクが空の万年筆',
  416. '色あせたお守り',
  417. '使い込まれたパイプ',
  418. 'よれた手帳',
  419. '読み込まれた本',
  420. 'ケースに入った楽器',
  421. '綺麗な鈴',
  422. '写真の入ったロケット',
  423. '古びた鍵',
  424. '汚れた帽子',
  425. '片耳分のピアス',
  426. '一房の髪',
  427. '血塗られたストール',
  428. '裂けた服',
  429. 'ヒビの入ったゴーグル',
  430. '壊れた眼鏡',
  431. '曇ったモノクル',
  432. '革製の眼帯',
  433. 'ボロボロの財布',
  434. 'よく手入れされた工具',
  435. '止まった腕時計',
  436. '子ども用の傘',
  437. '千切れたネックレス',
  438. '開かない懐中時計',
  439. '一組のダイス'
  440. ],
  441. },
  442. 'EXT' => {
  443. name: "専門能力表",
  444. type: 'D66',
  445. table: [
  446. 'メンタル 分類:準備',
  447. '宗教 分類:準備',
  448. '危険物 分類:準備',
  449. '化学 分類:準備',
  450. '狩猟 分類:準備',
  451. '警備 分類:準備',
  452. '採掘 分類:準備',
  453. 'トレーニング 分類:準備',
  454. '輸送・保管 分類:準備',
  455. 'サバイバル 分類:準備',
  456. '通信 分類:調査',
  457. '運転 分類:調査',
  458. '探偵 分類:調査',
  459. '地理 分類:調査',
  460. 'ドローン 分類:調査',
  461. '交渉 分類:調査',
  462. '文献調査 分類:調査',
  463. 'IT 分類:調査',
  464. '建築 分類:調査',
  465. '土木 分類:復興',
  466. '農業・畜産 分類:復興',
  467. '醸造 分類:復興',
  468. '教育 分類:復興',
  469. '公衆衛生 分類:復興',
  470. '治安 分類:復興',
  471. '電気 分類:復興',
  472. '機械 分類:復興',
  473. '芸術・芸能 分類:復興',
  474. '単純作業 分類:日常',
  475. 'ゲーム 分類:日常',
  476. '調理 分類:日常',
  477. '医療 分類:日常',
  478. 'スポーツ 分類:日常',
  479. 'ナイトビジネス 分類:日常',
  480. '祭事 分類:日常',
  481. '商売 分類:日常'
  482. ],
  483. },
  484. 'CAT' => {
  485. name: "コロッサル行動表",
  486. type: '1D6',
  487. table: [
  488. 'ZOWが急速に拡大してゆく!左右いずれかのエリアをZOWにする。対象エリアはZOWとなり、既存のイベントは消滅する。対象エリアは相談して選択し、そのエリアのイベントは消滅する。',
  489. 'あのコロッサルの反応は……。コロッサルの情報をひとつ得る。',
  490. '何もしない。',
  491. '何もしない。',
  492. '何もしない。',
  493. '何もしない。'
  494. ],
  495. },
  496. }.freeze
  497. 1 register_prefix('\d*CH', "B6T", "CNP", TABLES.keys)
  498. end
  499. end
  500. end

lib/bcdice/game_system/Comes.rb

100.0% lines covered

100.0% branches covered

15 relevant lines. 15 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Comes < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Comes'
  7. # ゲームシステム名
  8. 1 NAME = 'カムズ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'かむす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・各種表
  14.  判定ペナルティ表 PT
  15. INFO_MESSAGE_TEXT
  16. 1 def initialize(command)
  17. 2 super(command)
  18. 2 @sort_add_dice = true
  19. 2 @d66_sort_type = D66SortType::ASC
  20. end
  21. 1 def eval_game_system_specific_command(command)
  22. 2 return roll_tables(command, self.class::TABLES)
  23. end
  24. TABLES = {
  25. 1 'PT' => DiceTable::Table.new(
  26. '判定ペナルティ表',
  27. '1D6',
  28. [
  29. '恐ろしい目に合う。『恐怖』を与える。',
  30. '今見ているものを理解できない。『混乱』を与える。',
  31. '我を忘れて見とれてしまう。『魅了』を与える。',
  32. '思わぬ遠回りをしてしまう。『疲労』を与える。',
  33. '大きな失態を演じてしまう。『負傷』を与える。',
  34. '別の困難が立ちはだかる。新たに判定を行わせる。',
  35. ]
  36. )
  37. }.freeze
  38. 1 register_prefix(TABLES.keys)
  39. end
  40. end
  41. end

lib/bcdice/game_system/ConvictorDrive.rb

100.0% lines covered

100.0% branches covered

32 relevant lines. 32 lines covered and 0 lines missed.
6 total branches, 6 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/base'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class ConvictorDrive < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'ConvictorDrive'
  8. # ゲームシステム名
  9. 1 NAME = 'コンヴィクター・ドライブ'
  10. # ゲームシステム名の読みがな
  11. #
  12. # 「ゲームシステム名の読みがなの設定方法」(docs/dicebot_sort_key.md)を参考にして
  13. # 設定してください
  14. 1 SORT_KEY = 'こんういくたあとらいふ'
  15. # ダイスボットの使い方
  16. 1 HELP_MESSAGE = <<~MESSAGETEXT
  17. xCD@z>=y: x個の10面ダイスで目標値y(省略時5)、クリティカルラインz(省略時10)の判定を行う。
  18. SLT: 技能レベル表を振る
  19. DCT: 遅延イベント表を振る
  20. MESSAGETEXT
  21. TABLES = {
  22. 1 "SLT" => DiceTable::Table.new(
  23. "技能ランク表",
  24. "2D10",
  25. [
  26. "ランク外",
  27. "E-",
  28. "E",
  29. "E+",
  30. "D-",
  31. "D",
  32. "D+",
  33. "C-",
  34. "C",
  35. "C+",
  36. "B-",
  37. "B",
  38. "B+",
  39. "A-",
  40. "A",
  41. "A+",
  42. "S-",
  43. "S",
  44. "S+",
  45. ]
  46. ),
  47. "DCT" => DiceTable::Table.new(
  48. "遅延イベント表",
  49. "1D10",
  50. [
  51. "状況遅延Ⅰ(全員の初期リソースを-1する)",
  52. "状況遅延Ⅱ(全員の初期リソースを-1する)",
  53. "状況遅延Ⅲ(全員の初期リソースを-2する)",
  54. "武装を許すⅠ(ボスの攻撃ダイスを+1dする)",
  55. "武装を許すⅡ(脅威度4以下のエネミーの攻撃ダイスを2体まで+1dする)",
  56. "武装を許すⅢ(脅威度3以下のエネミーの攻撃ダイスを1体+2dする)",
  57. "緊急出撃Ⅰ(ランダムなPCのHPを-1する)",
  58. "緊急出撃Ⅱ(ランダムなPCのHPを-1する)",
  59. "緊急出撃Ⅲ(ランダムなPC2人のHPを-1する)",
  60. "絶望(ダイスを二度振り、二つ適用する)",
  61. ]
  62. ),
  63. }.freeze
  64. # ダイスボットで使用するコマンドを配列で列挙する
  65. 1 register_prefix("[-+*0-9\(\)]*CD", TABLES.keys)
  66. 1 def initialize(command)
  67. 10 super(command)
  68. 10 @sides_implicit_d = 10
  69. end
  70. 1 def eval_game_system_specific_command(command)
  71. 10 debug("eval_game_system_specific_command Begin")
  72. 10 return roll_command(command) || roll_tables(command, TABLES)
  73. end
  74. 1 def roll_command(command)
  75. 10 parser = Command::Parser.new('CD', round_type: round_type)
  76. .has_prefix_number
  77. .enable_critical
  78. .restrict_cmp_op_to(:>=, nil)
  79. 10 cmd = parser.parse(command)
  80. 10 else: 6 then: 4 unless cmd
  81. 4 return nil
  82. end
  83. 6 dice_list = @randomizer.roll_barabara(cmd.prefix_number, 10)
  84. 6 target_num = cmd.target_number || 5
  85. 6 then: 4 else: 2 critical = cmd.critical&.clamp(target_num, 10) || 10
  86. 36 succeed_num = dice_list.count { |x| x >= target_num }
  87. 36 critical_num = dice_list.count { |x| x >= critical }
  88. text = [
  89. 6 cmd.to_s,
  90. dice_list.join(','),
  91. 6 then: 3 else: 3 critical_num > 0 ? "クリティカル数#{critical_num}" : nil,
  92. "成功数#{succeed_num + critical_num}",
  93. ].compact.join(" > ")
  94. 6 return Result.new.tap do |r|
  95. 6 r.success = succeed_num > 0
  96. 6 r.critical = critical_num > 0
  97. 6 r.text = text
  98. end
  99. end
  100. end
  101. end
  102. end

lib/bcdice/game_system/CrashWorld.rb

100.0% lines covered

92.31% branches covered

36 relevant lines. 36 lines covered and 0 lines missed.
13 total branches, 12 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class CrashWorld < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'CrashWorld'
  7. # ゲームシステム名
  8. 1 NAME = '墜落世界'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ついらくせかい'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定 CWn
  14. 初期目標値n (必須)
  15. 例・CW8
  16. INFO_MESSAGE_TEXT
  17. 1 register_prefix('CW')
  18. 1 def eval_game_system_specific_command(command)
  19. 11 result = nil
  20. 11 else: 0 case command
  21. when: 11 when /CW(\d+)/i
  22. 11 result = getCrashWorldRoll(Regexp.last_match(1).to_i)
  23. end
  24. 11 return result
  25. end
  26. 1 def getCrashWorldRoll(target)
  27. 11 debug("target", target)
  28. 11 output = "("
  29. 11 isEnd = false
  30. 11 successness = 0
  31. 11 num = 0
  32. 11 body: 53 while !isEnd
  33. 53 num = @randomizer.roll_once(12)
  34. # 振った数字を出力へ書き足す
  35. 53 then: 11 if output == "("
  36. 11 output = "(#{num}"
  37. else: 42 else
  38. 42 output = "#{output}, #{num}"
  39. end
  40. 53 if num <= target || num == 11
  41. then: 42 # 成功/クリティカル(11)。 次回の目標値を変更して継続
  42. 42 target = num
  43. 42 else: 11 successness += 1
  44. 11 elsif num == 12
  45. then: 2 # ファンブルなら終了。
  46. 2 isEnd = true
  47. else
  48. else: 9 # target < num < 11で終了
  49. 9 isEnd = true
  50. end
  51. end
  52. 11 else: 9 if num == 12
  53. then: 2 # ファンブルの時、成功度は0
  54. 2 successness = 0
  55. end
  56. 11 output = "#{output}) 成功度 : #{successness}"
  57. 11 then: 2 else: 9 if num == 12
  58. 2 output = "#{output} ファンブル"
  59. end
  60. 11 return output
  61. end
  62. end
  63. end
  64. end

lib/bcdice/game_system/Cthulhu.rb

97.78% lines covered

91.11% branches covered

135 relevant lines. 132 lines covered and 3 lines missed.
45 total branches, 41 branches covered and 4 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/arithmetic_evaluator'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Cthulhu < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'Cthulhu'
  8. # ゲームシステム名
  9. 1 NAME = 'クトゥルフ神話TRPG'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'くとうるふしんわTRPG'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. c=クリティカル値 / f=ファンブル値 / s=スペシャル
  15. 1d100<=n c・f・sすべてオフ(単純な数値比較判定のみ行います)
  16. ・cfs判定付き判定コマンド
  17. CC 1d100ロールを行う c=1、f=100
  18. CCB 同上、c=5、f=96
  19. 例:CC<=80 (技能値80で行為判定。1%ルールでcf適用)
  20. 例:CCB<=55 (技能値55で行為判定。5%ルールでcf適用)
  21. ・組み合わせロールについて
  22. CBR(x,y) c=1、f=100
  23. CBRB(x,y) c=5、f=96
  24. ・抵抗表ロールについて
  25. RES(x-y) c=1、f=100
  26. RESB(x-y) c=5、f=96
  27. ※故障ナンバー判定
  28. ・CC(x) c=1、f=100
  29. x=故障ナンバー。出目x以上が出た上で、ファンブルが同時に発生した場合、共に出力する(テキスト「ファンブル&故障」)
  30. ファンブルでない場合、成功・失敗に関わらずテキスト「故障」のみを出力する(成功・失敗を出力せず、上書きしたものを出力する形)
  31. ・CCB(x) c=5、f=96
  32. 同上
  33. INFO_MESSAGE_TEXT
  34. 1 register_prefix('CCB?', 'RESB?', 'CBRB?')
  35. 1 def initialize(command)
  36. 513 super(command)
  37. 513 @special_percentage = 20
  38. 513 @critical_percentage = 1
  39. 513 @fumble_percentage = 1
  40. end
  41. 1 def eval_game_system_specific_command(command)
  42. 503 else: 0 case command
  43. when /CCB/i
  44. when: 113 # 5%
  45. 113 @critical_percentage = 5
  46. 113 @fumble_percentage = 5
  47. 113 return getCheckResult(command)
  48. when /CC/i
  49. when: 98 # 1%
  50. 98 @critical_percentage = 1
  51. 98 @fumble_percentage = 1
  52. 98 return getCheckResult(command)
  53. when /RESB/i
  54. when: 77 # 5%
  55. 77 @critical_percentage = 5
  56. 77 @fumble_percentage = 5
  57. 77 return getRegistResult(command)
  58. when /CBRB/i
  59. when: 68 # 5%
  60. 68 @critical_percentage = 5
  61. 68 @fumble_percentage = 5
  62. 68 return getCombineRoll(command)
  63. when /RES/i
  64. when: 82 # 1%
  65. 82 @critical_percentage = 1
  66. 82 @fumble_percentage = 1
  67. 82 return getRegistResult(command)
  68. when /CBR/i
  69. when: 65 # 1%
  70. 65 @critical_percentage = 1
  71. 65 @fumble_percentage = 1
  72. 65 return getCombineRoll(command)
  73. end
  74. return nil
  75. end
  76. 1 private
  77. 1 def getCheckResult(command)
  78. 211 m = %r{^CCB?(\d+)?(?:<=([+-/*\d]+))?$}i.match(command)
  79. 211 else: 205 then: 6 unless m
  80. 6 return nil
  81. end
  82. 205 broken_num = m[1].to_i
  83. 205 diff = ArithmeticEvaluator.eval(m[2])
  84. 205 then: 10 else: 195 if diff <= 0
  85. 10 total = @randomizer.roll_once(100)
  86. 10 return Result.new("(1D100) > #{total}")
  87. end
  88. 195 expr = "(1D100<=#{diff})"
  89. 195 then: 40 else: 155 if broken_num > 0
  90. 40 expr += " #{translate('Cthulhu.broken_number')}[#{broken_num}]"
  91. end
  92. 195 total = @randomizer.roll_once(100)
  93. 195 compare_result = compare(total, diff, broken_num)
  94. 195 compare_result.to_result.tap do |r|
  95. 195 r.text = "#{expr} > #{total} > #{compare_result.text}"
  96. end
  97. end
  98. 1 class CompareResult
  99. 1 include Translate
  100. 1 attr_accessor :success, :failure, :critical, :fumble, :special, :broken
  101. 1 def initialize(locale)
  102. 596 @locale = locale
  103. 596 @success = false
  104. 596 @failure = false
  105. 596 @critical = false
  106. 596 @fumble = false
  107. 596 @special = false
  108. 596 @broke = false
  109. end
  110. 1 def text
  111. 596 then: 68 if critical && special
  112. 68 else: 528 translate("Cthulhu.critical_special")
  113. 528 then: 0 elsif critical
  114. else: 528 translate("Cthulhu.critical")
  115. 528 then: 80 elsif special
  116. 80 else: 448 translate("Cthulhu.special")
  117. 448 then: 170 elsif success
  118. 170 else: 278 translate("success")
  119. 278 then: 15 elsif broken && fumble
  120. 15 else: 263 "#{translate('Cthulhu.fumble')}/#{translate('Cthulhu.broken')}"
  121. 263 then: 15 elsif broken
  122. 15 else: 248 translate("Cthulhu.broken")
  123. 248 then: 70 elsif fumble
  124. 70 else: 178 translate("Cthulhu.fumble")
  125. 178 then: 178 else: 0 elsif failure
  126. 178 translate("failure")
  127. end
  128. end
  129. 1 def to_result
  130. 330 Result.new.tap do |r|
  131. 330 r.success = success
  132. 330 r.failure = failure
  133. 330 r.critical = critical
  134. 330 r.fumble = fumble
  135. end
  136. end
  137. end
  138. 1 def compare(total, target, broken_number = 0)
  139. 596 result = CompareResult.new(@locale)
  140. 596 target_special = (target * @special_percentage / 100).clamp(1, 100)
  141. 596 then: 328 if (total <= target) && (total < 100)
  142. 328 result.success = true
  143. 328 result.special = total <= target_special
  144. 328 result.critical = total <= @critical_percentage
  145. else: 268 else
  146. 268 result.failure = true
  147. 268 result.fumble = total >= (101 - @fumble_percentage)
  148. end
  149. 596 then: 30 else: 566 if broken_number > 0 && total >= broken_number
  150. 30 result.broken = true
  151. 30 result.failure = true
  152. 30 result.success = false
  153. 30 result.special = false
  154. 30 result.critical = false
  155. end
  156. 596 return result
  157. end
  158. 1 def getRegistResult(command)
  159. 159 m = /^RESB?(-?\d+)$/i.match(command)
  160. 159 else: 155 then: 4 unless m
  161. 4 return nil
  162. end
  163. 155 value = m[1].to_i
  164. 155 target = value * 5 + 50
  165. 155 then: 10 else: 145 if target < 5
  166. 10 return Result.failure("(1d100<=#{target}) > #{translate('Cthulhu.automatic_failure')}")
  167. end
  168. 145 then: 10 else: 135 if target > 95
  169. 10 return Result.success("(1d100<=#{target}) > #{translate('Cthulhu.automatic_success')}")
  170. end
  171. # 通常判定
  172. 135 total_n = @randomizer.roll_once(100)
  173. 135 compare_result = compare(total_n, target)
  174. 135 compare_result.to_result.tap do |r|
  175. 135 r.text = "(1d100<=#{target}) > #{total_n} > #{compare_result.text}"
  176. end
  177. end
  178. 1 def getCombineRoll(command)
  179. 133 m = /^CBR(B)?\((\d+),(\d+)\)$/i.match(command)
  180. 133 else: 133 then: 0 unless m
  181. return nil
  182. end
  183. 133 diff_1 = m[2].to_i
  184. 133 diff_2 = m[3].to_i
  185. 133 total = @randomizer.roll_once(100)
  186. 133 result_1 = compare(total, diff_1)
  187. 133 result_2 = compare(total, diff_2)
  188. rank =
  189. 133 then: 40 if result_1.success && result_2.success
  190. 40 else: 93 translate("success")
  191. 93 then: 53 elsif result_1.success || result_2.success
  192. 53 translate("Cthulhu.partial_success")
  193. else: 40 else
  194. 40 translate("failure")
  195. end
  196. 133 Result.new.tap do |r|
  197. 133 r.text = "(1d100<=#{diff_1},#{diff_2}) > #{total}[#{result_1.text},#{result_2.text}] > #{rank}"
  198. 133 r.critical = result_1.critical || result_2.critical
  199. 133 r.fumble = result_1.fumble || result_2.fumble
  200. 133 r.condition = result_1.success || result_2.success
  201. end
  202. end
  203. end
  204. end
  205. end

lib/bcdice/game_system/Cthulhu7th.rb

99.29% lines covered

95.16% branches covered

140 relevant lines. 139 lines covered and 1 lines missed.
62 total branches, 59 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/cthulhu7th/rollable"
  3. 1 require "bcdice/game_system/cthulhu7th/full_auto"
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class Cthulhu7th < Base
  7. # ゲームシステムの識別子
  8. 1 ID = 'Cthulhu7th'
  9. # ゲームシステム名
  10. 1 NAME = '新クトゥルフ神話TRPG'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = 'しんくとうるふしんわTRPG'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  15. ・判定 CC(x)<=(目標値)
  16.  x:ボーナス・ペナルティダイス。省略可。
  17.  目標値が無くても1D100は表示される。
  18.  ファンブル/失敗/ レギュラー成功/ハード成功/
  19.  イクストリーム成功/クリティカル を自動判定。
  20.  例)CC<=30 CC(2)<=50 CC(+2)<=50 CC(-1)<=75 CC-1<=50 CC1<=65 CC+1<=65 CC
  21. ・技能ロールの難易度指定 CC(x)<=(目標値)(難易度)
  22.  目標値の後に難易度を指定することで
  23.  成功/失敗/クリティカル/ファンブル を自動判定する。
  24.  難易度の指定:
  25.   r:レギュラー h:ハード e:イクストリーム c:クリティカル
  26.  例)CC<=70r CC1<=60h CC-2<=50e CC2<=99c
  27. ・組み合わせ判定 (CBR(x,y))
  28.  目標値 x と y で%ロールを行い、成否を判定。
  29.  例)CBR(50,20)
  30. ・自動火器の射撃判定 FAR(w,x,y,z,d,v)
  31.  w:弾丸の数(1~100)、x:技能値(1~100)、y:故障ナンバー、
  32.  z:ボーナス・ペナルティダイス(-2~2)。省略可。
  33.  d:指定難易度で連射を終える(レギュラー:r,ハード:h,イクストリーム:e)。省略可。
  34.  v:ボレーの弾丸の数を変更する。省略可。
  35.  命中数と貫通数、残弾数のみ算出。ダメージ算出はありません。
  36. 例)FAR(25,70,98) FAR(50,80,98,-1) far(30,70,99,1,R)
  37.   far(25,88,96,2,h,5) FaR(40,77,100,,e,4) fAr(20,47,100,,,3)
  38. ・各種表
  39.  【狂気関連】
  40.  ・狂気の発作(リアルタイム)(Bouts of Madness Real Time) BMR
  41.  ・狂気の発作(サマリー)(Bouts of Madness Summary) BMS
  42.  ・恐怖症(Sample Phobias)表 PH/マニア(Sample Manias)表 MA
  43.  【魔術関連】
  44.  ・プッシュ時のキャスティング・ロール(Casting Roll)の失敗表
  45.   強力でない呪文の場合 FCL/強力な呪文の場合 FCM
  46. INFO_MESSAGE_TEXT
  47. 1 register_prefix('CC', 'CBR', 'FAR', 'BMR', 'BMS', 'FCL', 'FCM', 'PH', 'MA')
  48. 1 def eval_game_system_specific_command(command)
  49. 152 else: 0 case command
  50. when: 51 when /^CC/i
  51. 51 skill_roll(command)
  52. when: 12 when /^CBR/i
  53. 12 combine_roll(command)
  54. when: 75 when /^FAR/i
  55. 75 getFullAutoResult(command)
  56. when: 1 when "BMR" # 狂気の発作(リアルタイム)
  57. 1 roll_bmr_table()
  58. when: 1 when "BMS" # 狂気の発作(サマリー)
  59. 1 roll_bms_table()
  60. when: 3 when "FCL" # キャスティング・ロールのプッシュに失敗した場合(小)
  61. 3 roll_1d8_table("キャスティング・ロール失敗(小)表", FAILED_CASTING_L_TABLE)
  62. when: 3 when "FCM" # キャスティング・ロールのプッシュに失敗した場合(大)
  63. 3 roll_1d8_table("キャスティング・ロール失敗(大)表", FAILED_CASTING_M_TABLE)
  64. when: 3 when "PH" # 恐怖症表
  65. 3 roll_1d100_table("恐怖症表", PHOBIAS_TABLE)
  66. when: 3 when "MA" # マニア表
  67. 3 roll_1d100_table("マニア表", MANIAS_TABLE)
  68. end
  69. end
  70. 1 class ResultLevel
  71. 1 LEVEL = [
  72. :fumble,
  73. :failure,
  74. :success,
  75. :regular_success,
  76. :hard_success,
  77. :extreme_success,
  78. :critical,
  79. ].freeze
  80. 1 LEVEL_TO_S = {
  81. critical: "クリティカル",
  82. extreme_success: "イクストリーム成功",
  83. hard_success: "ハード成功",
  84. regular_success: "レギュラー成功",
  85. success: "成功",
  86. fumble: "ファンブル",
  87. failure: "失敗",
  88. }.freeze
  89. 1 def self.with_difficulty_level(total, difficulty)
  90. 15 then: 9 else: 6 fumble = difficulty < 50 ? 96 : 100
  91. 15 then: 2 if total == 1
  92. 2 else: 13 ResultLevel.new(:critical)
  93. 13 then: 5 elsif total >= fumble
  94. 5 else: 8 ResultLevel.new(:fumble)
  95. 8 then: 3 elsif total <= difficulty
  96. 3 ResultLevel.new(:success)
  97. else: 5 else
  98. 5 ResultLevel.new(:failure)
  99. end
  100. end
  101. 1 def self.from_values(total, difficulty, fumbleable = false)
  102. 208 then: 84 else: 124 fumble = difficulty < 50 || fumbleable ? 96 : 100
  103. 208 then: 15 if total == 1
  104. 15 else: 193 ResultLevel.new(:critical)
  105. 193 then: 29 elsif total >= fumble
  106. 29 else: 164 ResultLevel.new(:fumble)
  107. 164 then: 36 elsif total <= (difficulty / 5)
  108. 36 else: 128 ResultLevel.new(:extreme_success)
  109. 128 then: 32 elsif total <= (difficulty / 2)
  110. 32 else: 96 ResultLevel.new(:hard_success)
  111. 96 then: 55 elsif total <= difficulty
  112. 55 ResultLevel.new(:regular_success)
  113. else: 41 else
  114. 41 ResultLevel.new(:failure)
  115. end
  116. end
  117. 1 def initialize(level)
  118. 223 @level = level
  119. 223 @level_index = LEVEL.index(level)
  120. 223 else: 223 then: 0 raise ArgumentError unless @level_index
  121. end
  122. 1 def success?
  123. 92 @level_index >= LEVEL.index(:success)
  124. end
  125. 1 def failure?
  126. 17 @level_index <= LEVEL.index(:failure)
  127. end
  128. 1 def critical?
  129. 42 @level == :critical
  130. end
  131. 1 def fumble?
  132. 42 @level == :fumble
  133. end
  134. 1 def to_s
  135. 223 LEVEL_TO_S[@level]
  136. end
  137. end
  138. 1 private
  139. 1 include Rollable
  140. 1 def roll_1d8_table(table_name, table)
  141. 6 total_n = @randomizer.roll_once(8)
  142. 6 index = total_n - 1
  143. 6 text = table[index]
  144. 6 return "#{table_name}(#{total_n}) > #{text}"
  145. end
  146. 1 def roll_1d100_table(table_name, table)
  147. 12 total_n = @randomizer.roll_once(100)
  148. 12 index = total_n - 1
  149. 12 text = table[index]
  150. 12 return "#{table_name}(#{total_n}) > #{text}"
  151. end
  152. 1 def skill_roll(command)
  153. 53 m = /^CC([-+]?\d+)?(?:<=(\d+)([RHEC])?)?$/.match(command)
  154. 53 else: 53 then: 0 unless m
  155. return nil
  156. end
  157. 53 bonus_dice = m[1].to_i
  158. 53 then: 46 else: 7 difficulty = m[2]&.to_i
  159. 53 difficulty_level = m[3]
  160. 53 then: 2 if difficulty == 0
  161. 2 else: 51 difficulty = nil
  162. 51 then: 4 elsif difficulty_level == "H"
  163. 4 else: 47 difficulty /= 2
  164. 47 then: 3 elsif difficulty_level == "E"
  165. 3 else: 44 difficulty /= 5
  166. 44 then: 3 else: 41 elsif difficulty_level == "C"
  167. 3 difficulty = 0
  168. end
  169. 53 then: 3 else: 50 if bonus_dice == 0 && difficulty.nil?
  170. 3 dice = @randomizer.roll_once(100)
  171. 3 return "(1D100) > #{dice}"
  172. end
  173. 50 then: 2 else: 48 if bonus_dice.abs > 100
  174. 2 return "ボーナス・ペナルティダイスの値は-100以上、100以下としてください"
  175. end
  176. 48 total, total_list = roll_with_bonus(bonus_dice)
  177. 48 then: 6 else: 42 expr = difficulty.nil? ? "1D100" : "1D100<=#{difficulty}"
  178. result =
  179. 48 then: 15 if difficulty_level
  180. 15 else: 33 ResultLevel.with_difficulty_level(total, difficulty)
  181. 33 then: 27 else: 6 elsif difficulty
  182. 27 ResultLevel.from_values(total, difficulty)
  183. end
  184. sequence = [
  185. 48 "(#{expr}) ボーナス・ペナルティダイス[#{bonus_dice}]",
  186. total_list.join(", "),
  187. total,
  188. result,
  189. ].compact
  190. 48 Result.new.tap do |r|
  191. 48 r.text = sequence.join(" > ")
  192. 48 then: 42 else: 6 if result
  193. 42 r.condition = result.success?
  194. 42 r.critical = result.critical?
  195. 42 r.fumble = result.fumble?
  196. end
  197. end
  198. end
  199. 1 def getFullAutoResult(command)
  200. 76 FullAuto.eval(command, @randomizer)
  201. end
  202. 1 def combine_roll(command)
  203. 13 m = /^CBR\((\d+),(\d+)\)$/.match(command)
  204. 13 else: 12 then: 1 return nil unless m
  205. 12 difficulty_1 = m[1].to_i
  206. 12 difficulty_2 = m[2].to_i
  207. 12 total = @randomizer.roll_once(100)
  208. 12 result_1 = ResultLevel.from_values(total, difficulty_1)
  209. 12 result_2 = ResultLevel.from_values(total, difficulty_2)
  210. rank =
  211. 12 then: 5 if result_1.success? && result_2.success?
  212. 5 else: 7 "成功"
  213. 7 then: 5 elsif result_1.success? || result_2.success?
  214. 5 "部分的成功"
  215. else: 2 else
  216. 2 "失敗"
  217. end
  218. 12 Result.new.tap do |r|
  219. 12 r.text = "(1d100<=#{difficulty_1},#{difficulty_2}) > #{total}[#{result_1},#{result_2}] > #{rank}"
  220. 12 r.success = result_1.success? && result_2.success?
  221. 12 r.failure = result_1.failure? && result_2.failure?
  222. end
  223. end
  224. # 表一式
  225. # 即時の恐怖症表
  226. 1 def roll_bmr_table()
  227. 1 total_n = @randomizer.roll_once(10)
  228. 1 text = MADNESS_REAL_TIME_TABLE[total_n - 1]
  229. 1 time_n = @randomizer.roll_once(10)
  230. 1 return "狂気の発作(リアルタイム)(#{total_n}) > #{text}(1D10>#{time_n}ラウンド)"
  231. end
  232. 1 MADNESS_REAL_TIME_TABLE = [
  233. '健忘症:探索者は、最後に安全な場所にいた時からあとに起こった出来事の記憶を持たない。例えば、朝食を食べていた次の瞬間には怪物と向かい合っている。これは1D10ラウンド続く。',
  234. '身体症状症:探索者は1D10ラウンドの間、狂気によって視覚や聴覚に異常が生じたり、四肢の1つまたは複数が動かなくなる。',
  235. '暴力衝動:赤い霧が探索者に降り、1D10ラウンドの間、抑えの利かない暴力と破壊を敵味方を問わず周囲に向かって爆発させる。',
  236. '偏執症:探索者は1D10ラウンドの間、重い偏執症に襲われる。誰もが探索者に襲い掛かろうとしている。信用できる者はいない。監視されている。裏切ったやつがいる。これはわなだ。',
  237. '重要な人々:探索者のバックストーリーの重要な人々を見直す。探索者はその場にいた人物を、自分にとっての重要な人々だと思い込む。人間関係の性質を考慮した上で、探索者はそれに従って行動する。1D10ラウンド続く。',
  238. '失神:探索者は失神する。1D10ラウンド後に回復する。',
  239. 'パニックになって逃亡する:探索者は利用できるあらゆる手段を使って、可能なかぎり遠くへ逃げ出さずにはいられない。それが唯一の車両を奪って仲間を置き去りにすることであっても。探索者は1D10ラウンドの間、逃げ続ける。',
  240. '身体的ヒステリーもしくは感情爆発:探索者は1D10ラウンドの間、笑ったり、泣いたり、あるいは叫んだりし続け、行動できなくなる。',
  241. '恐怖症:探索者は新しい恐怖症に陥る。恐怖症表(PHコマンド)をロールするか、キーパーが恐怖症を1つ選ぶ。恐怖症の原因は存在しなくとも、その探索者は次の1D10ラウンドの間、それがそこにあると思い込む。',
  242. 'マニア:探索者は新しいマニアに陥る。マニア表(MAコマンド)をロールするか、キーパーがマニアを1つ選ぶ。その探索者は次の1D10ラウンドの間、自分の新しいマニアに没頭しようとする。'
  243. ].freeze
  244. # 略式の恐怖表
  245. 1 def roll_bms_table()
  246. 1 total_n = @randomizer.roll_once(10)
  247. 1 text = MADNESS_SUMMARY_TABLE[total_n - 1]
  248. 1 time_n = @randomizer.roll_once(10)
  249. 1 return "狂気の発作(サマリー)(#{total_n}) > #{text}(1D10>#{time_n}時間)"
  250. end
  251. 1 MADNESS_SUMMARY_TABLE = [
  252. '健忘症:探索者が意識を取り戻すと、見知らぬ場所におり、自分が誰かもわからない。記憶は時間をかけてゆっくりと戻るだろう。',
  253. '盗難:探索者は1D10時間後に意識を取り戻すが、盗難の被害を受けている。傷つけられてはいない。探索者が秘蔵の品を身に着けていた場合(「探索者のバックストーリー」参照)、〈幸運〉ロールを行い、それが盗まれていないか判定する。値打ちのあるものはすべて自動的に失われる。',
  254. '暴行:探索者は1D10時間後に意識を取り戻し、自分が暴行を受け、傷ついていることに気づく。耐久力は狂気に陥る前の半分に減少している。ただし重症は生じていない。盗まれたものはない。どのようにダメージが加えられたかは、キーパーに委ねられる。',
  255. '暴力:探索者は暴力と破壊の噴流を爆発させる。探索者が意識を取り戻した時、その行動を認識し記憶していることもあればそうでないこともある。探索者が暴力を振るった物、もしくは人、そして相手を殺してしまったのか、あるいは単に傷つけただけなのかはキーパーに委ねられる。',
  256. 'イデオロギー/信念:探索者のバックストーリーのイデオロギーと信念を参照する。探索者はこれらの1つの権化となり、急進的かつ狂気じみて、感情もあらわに主張するようになる。例えば、宗教に関係する者は、その後地下鉄で声高に福音を説教しているところを目撃されるかもしれない。',
  257. '重要な人々:探索者のバックストーリーの重要な人々を参照し、なぜその人物との関係が重要かを考える。時間がたってから(1D10時間以上)、探索者はその人物に近づくための最善の行動、そしてその人物との関係にとって最善の行動をとる。',
  258. '収容:探索者は精神療養施設あるいは警察の留置所で意識を取り戻す。探索者は徐々にそこにいたった出来事を思い出すかもしれない。',
  259. 'パニック:探索者は非常に遠い場所で意識を取り戻す。荒野で道に迷っているか、列車に乗っているか、長距離バスに乗っているかもしれない。',
  260. '恐怖症:探索者は新たな恐怖症を獲得する。恐怖症表(PHコマンド)をロールするか、キーパーがどれか1つ選ぶ。探索者は1D10時間後に意識を取り戻し、この新たな恐怖症の対象を避けるためにあらゆる努力をする。',
  261. 'マニア:探索者は新たなマニアを獲得する。マニア表(MAコマンド)をロールするか、キーパーがどれか1つ選ぶ。この狂気の発作の間、探索者はこの新たなマニアに完全に溺れているだろう。これがほかの人々に気づかれるかどうかは、キーパーとプレイヤーに委ねられる。'
  262. ].freeze
  263. # キャスティング・ロールのプッシュに失敗した場合(小)
  264. 1 FAILED_CASTING_L_TABLE = [
  265. '視界がぼんやりするか、あるいは一時的な失明。',
  266. '悲鳴、声、あるいはほかの雑音が肉体から発せられる。',
  267. '強風やほかの大気の現象。',
  268. '術者、ほかのその場に居合わせた者が出血する。あるいは環境(例えば、壁)から出血する。',
  269. '奇妙な幻視と幻覚。',
  270. 'その付近の小動物たちが爆発する。',
  271. '硫黄の悪臭。',
  272. 'クトゥルフ神話の怪物が偶然召喚される。'
  273. ].freeze
  274. # キャスティング・ロールのプッシュに失敗した場合(大)
  275. 1 FAILED_CASTING_M_TABLE = [
  276. '大地が震え、壁に亀裂が入って崩れる。',
  277. '叙事詩的な電撃。',
  278. '血が空から降る。',
  279. '術者の手がしなび、焼けただれる。',
  280. '術者は不自然に年をとる(年齢に+2D10歳、30ページの「年齢」を参照し、能力値に修正を適用すること)。',
  281. '強力な、あるいは無数のクトゥルフ神話存在が現れ、術者を手始めに、近くの全員を攻撃する!',
  282. '術者や近くの全員が遠い時代か場所に吸い込まれる。',
  283. 'クトゥルフ神話の神格が偶然招来される。'
  284. ].freeze
  285. # 恐怖症表
  286. 1 PHOBIAS_TABLE = [
  287. '入浴恐怖症:体、手、顔を洗うのが怖い。',
  288. '高所恐怖症:高いところが怖い。',
  289. '飛行恐怖症:飛ぶのが怖い。',
  290. '広場恐怖症:広場、公共の(混雑した)場所が怖い。',
  291. '鶏肉恐怖症:鶏肉が怖い。',
  292. 'ニンニク恐怖症:ニンニクが怖い。',
  293. '乗車恐怖症:車両の中にいたり車両に乗るのが怖い。',
  294. '風恐怖症:風が怖い。',
  295. '男性恐怖症:男性が怖い。',
  296. 'イングランド恐怖症:イングランド、もしくはイングランド文化などが怖い。',
  297. '花恐怖症:花が怖い。',
  298. '切断恐怖症:手足や指などが切断された人が怖い。',
  299. 'クモ恐怖症:クモが怖い。',
  300. '稲妻恐怖症:稲妻が怖い。',
  301. '廃墟恐怖症:廃墟が怖い。',
  302. '笛恐怖症:笛(フルート)が怖い。',
  303. '細菌恐怖症:細菌、バクテリアが怖い。',
  304. '銃弾恐怖症:投擲物や銃弾が怖い。',
  305. '落下恐怖症:落下が怖い。',
  306. '書物恐怖症:本が怖い。',
  307. '植物恐怖症:植物が怖い。',
  308. '美女恐怖症:美しい女性が怖い。',
  309. '低温恐怖症:冷たいものが怖い。',
  310. '時計恐怖症:時計が怖い。',
  311. '閉所恐怖症:壁に囲まれた場所が怖い。',
  312. '道化師恐怖症:道化師が怖い。',
  313. '犬恐怖症:犬が怖い。',
  314. '悪魔恐怖症:悪魔が怖い。',
  315. '群集恐怖症:人混みが怖い。',
  316. '歯科医恐怖症:歯科医が怖い。',
  317. '処分恐怖症:物を捨てるのが怖い(ためこみ症)',
  318. '毛皮恐怖症:毛皮が怖い。',
  319. '構断恐怖症:道路を横断するのが怖い。',
  320. '教会恐怖症:教会が怖い。',
  321. '鏡恐怖症:鏡が怖い。',
  322. 'ピン恐怖症:針やピンが怖い。',
  323. '昆虫恐怖症:昆虫が怖い。',
  324. '猫恐怖症:猫が怖い。',
  325. '橋恐怖症:橋を渡るのが怖い。',
  326. '老人恐怖症:老人や年をとることが怖い。',
  327. '女性恐怖症:女性が怖い。',
  328. '血液恐怖症:血が怖い。',
  329. '過失恐怖症:失敗が怖い。',
  330. '接触恐怖症:触ることが怖い。',
  331. '爬虫類恐怖症:爬虫類が怖い。',
  332. '霧恐怖症:霧が怖い。',
  333. '銃器恐怖症:銃器が怖い。',
  334. '水恐怖症:水が怖い。',
  335. '睡眠恐怖症:眠ったり、催眠状態に陥るのが怖い。',
  336. '医師恐怖症:医師が怖い。',
  337. '魚恐怖症:魚が怖い。',
  338. 'ゴキブリ恐怖症:ゴキブリが怖い。',
  339. '雷鳴恐怖症:雷鳴が怖い。',
  340. '野菜恐怖症:野菜が怖い。',
  341. '大騒音恐怖症:大きな騒音が怖い。',
  342. '湖恐怖症:湖が怖い。',
  343. '機械恐怖症:機械や装置が怖い。',
  344. '巨大物恐怖症:巨大なものが怖い。',
  345. '拘束恐怖症:縛られたり結びつけられたりするのが怖い。',
  346. '隕石恐怖症:流星や隕石が怖い。',
  347. '孤独恐怖症:独りでいることが怖い。',
  348. '汚染恐怖症:汚れたり汚染されたりするのが怖い。',
  349. '粘液恐怖症:粘液、粘体が怖い。',
  350. '死体恐怖症:死体が怖い。',
  351. '8恐怖症:8の数字が怖い。',
  352. '歯恐怖症:歯が怖い。',
  353. '夢恐怖症:夢が怖い。',
  354. '名称恐怖症:特定の言葉(1つまたは複数)を聞くのが怖い。',
  355. '蛇恐怖症:蛇が怖い。',
  356. '鳥恐怖症:鳥が怖い。',
  357. '寄生生物恐怖症:寄生生物が怖い。',
  358. '人形恐怖症:人形が怖い。',
  359. '恐食症:のみ込むこと食べること、もしくは食べられることが怖い。',
  360. '薬物恐怖症:薬物が怖い。',
  361. '幽霊恐怖症:幽霊が怖い。',
  362. '羞明:日光が怖い。',
  363. 'ひげ恐怖症:ひげが怖い',
  364. '河川恐怖症:川が怖い',
  365. 'アルコール恐怖症:アルコールやアルコール飲料が怖い。',
  366. '火恐怖症:火が怖い。',
  367. '魔術恐怖症:魔術が怖い。',
  368. '暗黒恐怖症:暗闇や夜が怖い。',
  369. '月恐怖症:月が怖い。',
  370. '鉄道恐怖症:列車の旅が怖い。',
  371. '星恐怖症:星が怖い。',
  372. '狭所恐怖症:狭いものや場所が怖い。',
  373. '対称恐怖症:左右対称が怖い。',
  374. '生き埋め恐怖症:生き埋めになることや墓地が怖い。',
  375. '雄牛恐怖症:雄牛が怖い。',
  376. '電話恐怖症:電話が怖い。',
  377. '奇形恐怖症:怪物が怖い。',
  378. '海洋恐怖症:海が怖い。',
  379. '手術恐怖症:外科手術が怖い。',
  380. '13恐怖症:13の数字が怖い。',
  381. '衣類恐怖症:衣服が怖い。',
  382. '魔女恐怖症:魔女と魔術が怖い。',
  383. '黄色恐怖症:黄色や「黄色」という言葉が怖い。',
  384. '外国語恐怖症:外国語が怖い。',
  385. '外国人恐怖症:外国人が怖い。',
  386. '動物恐怖症:動物が怖い。',
  387. ].freeze
  388. # マニア表
  389. 1 MANIAS_TABLE = [
  390. '洗浄マニア:自分の体を洗わずにはいられない。',
  391. '無為マニア:病的な優柔不断。',
  392. '暗闇マニア:暗黒に関する過度の嗜好。',
  393. '高所マニア:高い場所に登らずにはいられない。',
  394. '善良マニア:病的な親切。',
  395. '広場マニア:開けた場所にいたいという激しい願望。',
  396. '先鋭マニア:鋭いもの、とがったものへの執着。',
  397. '猫マニア:猫に関する異常な愛好心。',
  398. '疼痛性愛:痛みへの執着。',
  399. 'にんにくマニア:にんにくへの執着。',
  400. '乗り物マニア:車の中にいることへの執着。',
  401. '病的快活:不合理なほがらかさ。',
  402. '花マニア:花への執着。',
  403. '計算マニア:数への偏執的な没頭。',
  404. '浪費マニア:衝動的あるいは無謀な浪費。',
  405. '自己マニア:孤独への過度の嗜好。',
  406. 'バレエマニア:バレエに関する異常な愛好心。',
  407. '書籍約盗癖:本を盗みたいという強迫的衝動。',
  408. '書物マニア:本または読書、あるいはその両方への執着。',
  409. '歯ぎしりマニア:歯ぎしりしたいという強迫的衝動。',
  410. '悪霊マニア:誰かの中に邪悪な精霊がいるという病的な信念。',
  411. '自己愛マニア:自分自身の美への執着。',
  412. '地図マニア:いたる所の地図を見る制御不可能な強迫的衝動。',
  413. '飛び降りマニア:高い場所から跳躍することへの執着。',
  414. '寒冷マニア:冷たさ、または冷たいもの、あるいはその両方への異常な欲望。',
  415. '舞踏マニア:踊ることへの愛好もしくは制御不可能な熱狂。',
  416. '睡眠マニア:寝ることへの過度の願望。',
  417. '墓地マニア:墓地への執着。',
  418. '色彩マニア:特定の色への執着。',
  419. 'ピエロマニア:ピエロへの執着。',
  420. '遭遇マニア:恐ろしい状況を経験したいという強迫的衝動。',
  421. '殺害マニア:殺害への執着。',
  422. '悪魔マニア:誰かが悪魔にとりつかれているという病的な信念。',
  423. '皮膚マニア:人の皮膚を引っぱりたいという強迫的衝動。',
  424. '正義マニア:正義が完遂されるのを見たいという執着。',
  425. 'アルコールマニア:アルコールに関する異常な欲求。',
  426. '毛皮マニア:毛皮を所有することへの執着。',
  427. '贈り物マニア:贈り物を与えることへの執着。',
  428. '逃走マニア:逃走することへの迫的衝動。',
  429. '外出マニア:外を歩き回ることの強迫的衝動。',
  430. '自己中心マニア:不合理な自心の態度か自己崇拝。',
  431. '公職マニア:公的な職業に就きいという強欲な衝動。',
  432. '戦慄マニア:誰かが罪を犯したという病的な信念',
  433. '知識マニア:知識を得ることへ執着。',
  434. '静寂マニア:静寂であることへ強迫的衝動。',
  435. 'エーテルマニア:エーテルへの切望',
  436. '求婚マニア:奇妙な求婚をすることへの執着。',
  437. '笑いマニア:制御不可能な笑うことへの強迫的衝動。',
  438. '魔術マニア:魔女と魔術への執着。',
  439. '筆記マニア:すべてを書き留めることへの執着。',
  440. '裸体マニア:裸になりたいという強迫的衝動。',
  441. '幻想マニア:快い幻想(現実とは関係なく)にとらわれやすい異常な傾向。',
  442. '蟲マニア:蟲に関する過度の嗜好。',
  443. '火器マニア:火器への執着。',
  444. '水マニア:水に関する不合理な渇望。',
  445. '魚マニア:魚への執着。',
  446. 'アイコンマニア:像や肖像への執着。',
  447. 'アイドルマニア:偶像への執着または献身。',
  448. '情報マニア:事実を集めることへの過度の献身。',
  449. '絶叫マニア:叫ぶことへの説明できない強迫的衝動。',
  450. '窃盗マニア:盗むことへの説明できない強迫的衝動。',
  451. '騒音マニア:大きな、あるいは甲高い騒音を出すことへの制御不可能な強迫的衝動。',
  452. 'ひもマニア:ひもへの執着。',
  453. '宝くじマニア:宝くじに参加したいという極度の願望。',
  454. 'うつマニア:異常に深くふさぎ込む傾向。',
  455. '巨石マニア:環状列石/立石があると奇妙な考えにとらわれる異常な傾向。',
  456. '音楽マニア:音楽もしくは特定の旋律への執着。',
  457. '作詩マニア:詩を書くことへの強欲な願望。',
  458. '憎悪マニア:何らかの対象あるいはグループの何もかもを憎む執着。',
  459. '偏執マニア:ただ1つの思想やアイデアへの異常な執着。',
  460. '虚言マニア:異常なほどにうそをついたり、誇張して話す。',
  461. '疾病マニア:想像上の病気に苦められる幻想。',
  462. '記録マニア:あらゆるものを記録に残そうという強迫的衝動。',
  463. '名前マニア:人々、場所、ものなどの名前への執着',
  464. '単語マニア:ある単語を繰り返したいという押さえ切れない欲求。',
  465. '爪損傷マニア:指の爪をむしったりはがそうとする強迫的衝動。',
  466. '美食マニア:1種類の食物への異常な愛。',
  467. '不平マニア:不平を言うことへの異常な喜び。',
  468. '仮面マニア:仮面や覆面を着けたいという強迫的衝動。',
  469. '幽霊マニア:幽霊への執着。',
  470. '殺人マニア:殺人への病的な傾向。',
  471. '光線マニア:光への病的な願望。',
  472. '放浪マニア:社会の規範に背きたいという異常な欲望。',
  473. '長者マニア:富への強迫的な欲望。',
  474. '病的虚言マニア:うそをつきたくてたまらない強迫的衝動。',
  475. '放火マニア:火をつけることへの強迫的衝動。',
  476. '質問マニア:質問したいという激しい強迫的衝動。',
  477. '鼻マニア:鼻をいじりたいという強迫的衝動。',
  478. '落書きマニア:いらずら書きや落書きへの執着。',
  479. '列車マニア:列車と鉄道旅行への強い魅了。',
  480. '知性マニア:誰かが信じられないほど知的であるという幻想。',
  481. 'テクノマニア:新技術への執着。',
  482. 'タナトスマニア:誰かが死を招く魔術によって呪われているという信念。',
  483. '宗教マニア:その人が神であるという信仰。',
  484. 'かき傷マニア:かき傷をつけることへの強迫的衝動。',
  485. '手術マニア:外科手術を行なうことへの不合理な嗜好。',
  486. '抜毛マニア:自分の髪を引き抜くことへの切望。',
  487. '失明マニア:病的な視覚障害。',
  488. '異国マニア:外国のものへの執着。',
  489. '動物マニア:動物への正気でない溺愛。',
  490. ].freeze
  491. end
  492. end
  493. end

lib/bcdice/game_system/Cthulhu7th_ChineseTraditional.rb

99.29% lines covered

95.16% branches covered

140 relevant lines. 139 lines covered and 1 lines missed.
62 total branches, 59 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/Cthulhu7th_ChineseTraditional/rollable"
  3. 1 require "bcdice/game_system/Cthulhu7th_ChineseTraditional/full_auto"
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class Cthulhu7th_ChineseTraditional < Base
  7. # ゲームシステムの識別子
  8. 1 ID = 'Cthulhu7th:ChineseTraditional'
  9. # ゲームシステム名
  10. 1 NAME = '克蘇魯神話第7版'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = '国際化:Chinese Traditional:克蘇魯神話第7版'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  15. ・判定 CC(x)<=(目標值)
  16. x:獎勵或懲罰骰,可以省略。
  17. 即使沒有目標值,也會顯示1D100。
  18. 自動判定:大失敗/失敗/成功/一般成功/困難成功/極限成功/大成功。
  19. 例)CC<=30,CC2<=50,CC(+2)<=50,CC(-1)<=75,CC-1<=50,CC1<=65,CC+1<=65,CC
  20. ・技能擲骰的難度指定 CC(x)<=(目標值)(難度)
  21. 透過指定難度,大失敗/成功/失敗/大成功/失敗將自動判定。
  22. 指定難度:
  23. r:常規,h:困難,e:極限,c:大成功
  24. 例)CC<=70r,CC1<=60h,CC-2<=50e,CC2<=99c
  25. ・組合判定 (CBR(x,y))
  26. 對於目標值 x 和 y 進行百分比擲骰並判定成敗。
  27. 例)CBR(50,20)
  28. ・機關槍的射擊判定 FAR(w,x,y,z,d,v)
  29. w:子彈數量(1~100), x:技能值(1~100), y:故障值,
  30. z:獎勵或懲罰骰(-2~2),可以省略。
  31. d:指定難度以結束連射(常規:r,困難:h,極限:e),可以省略。
  32. v:更改彈藥的數量,可以省略。
  33. 只計算命中數和貫通數,剩餘彈藥數。傷害計算不包括在內。
  34. 例)FAR(25,70,98), FAR(50,80,98,-1), far(30,70,99,1,R)
  35. far(25,88,96,2,h,5), FaR(40,77,100,,e,4), fAr(20,47,100,,,3)
  36. ・各種表
  37. 【狂氣相關】
  38. ・即時型瘋狂檢定(Bouts of Madness Real Time) CCRT
  39. ・總結型瘋狂檢定(Bouts of Madness Summary) CCSU
  40. ・恐懼症表(Sample Phobias) CCPH/狂熱症表(Sample Manias) CCMA
  41. 【魔術相關】
  42. ・推骰時施法失敗擲骰表(Casting Roll)
  43. 弱小咒語的情況 CCCL/強力咒語的情況 CCPC
  44. INFO_MESSAGE_TEXT
  45. 1 register_prefix('CC', 'CBR', 'FAR', 'CCRT', 'CCSU', 'CCCL', 'CCPC', 'CCPH', 'CCMA')
  46. 1 def eval_game_system_specific_command(command)
  47. 151 else: 0 case command
  48. when: 12 when /^CBR/i
  49. 12 combine_roll(command)
  50. when: 75 when /^FAR/i
  51. 75 getFullAutoResult(command)
  52. when: 1 when "CCRT" # 狂氣の發作(即時)
  53. 1 roll_CCRT_table()
  54. when: 1 when "CCSU" # 狂気の發作(總結型)
  55. 1 roll_CCSU_table()
  56. when: 3 when "CCCL" # キャスティング・ロールのプッシュに失敗した場合(小)
  57. 3 roll_1d8_table("推骰時施法失敗擲骰表(小)", FAILED_CASTING_L_TABLE)
  58. when: 3 when "CCPC" # キャスティング・ロールのプッシュに失敗した場合(大)
  59. 3 roll_1d8_table("推骰時施法失敗擲骰表(大)", FAILED_CASTING_M_TABLE)
  60. when: 3 when "CCPH" # 恐懼症表
  61. 3 roll_1d100_table("恐懼症表", PHOBIAS_TABLE)
  62. when: 3 when "CCMA" # 狂熱症表
  63. 3 roll_1d100_table("狂熱症表", MANIAS_TABLE)
  64. when: 50 when /^CC/i
  65. 50 skill_roll(command)
  66. end
  67. end
  68. 1 class ResultLevel
  69. 1 LEVEL = [
  70. :fumble,
  71. :failure,
  72. :success,
  73. :regular_success,
  74. :hard_success,
  75. :extreme_success,
  76. :critical,
  77. ].freeze
  78. 1 LEVEL_TO_S = {
  79. critical: "大成功",
  80. extreme_success: "極限成功",
  81. hard_success: "困難成功",
  82. regular_success: "一般成功",
  83. success: "成功",
  84. fumble: "大失敗",
  85. failure: "失敗",
  86. }.freeze
  87. 1 def self.with_difficulty_level(total, difficulty)
  88. 15 then: 9 else: 6 fumble = difficulty < 50 ? 96 : 100
  89. 15 then: 2 if total == 1
  90. 2 else: 13 ResultLevel.new(:critical)
  91. 13 then: 5 elsif total >= fumble
  92. 5 else: 8 ResultLevel.new(:fumble)
  93. 8 then: 3 elsif total <= difficulty
  94. 3 ResultLevel.new(:success)
  95. else: 5 else
  96. 5 ResultLevel.new(:failure)
  97. end
  98. end
  99. 1 def self.from_values(total, difficulty, fumbleable = false)
  100. 204 then: 83 else: 121 fumble = difficulty < 50 || fumbleable ? 96 : 100
  101. 204 then: 15 if total == 1
  102. 15 else: 189 ResultLevel.new(:critical)
  103. 189 then: 29 elsif total >= fumble
  104. 29 else: 160 ResultLevel.new(:fumble)
  105. 160 then: 36 elsif total <= (difficulty / 5)
  106. 36 else: 124 ResultLevel.new(:extreme_success)
  107. 124 then: 31 elsif total <= (difficulty / 2)
  108. 31 else: 93 ResultLevel.new(:hard_success)
  109. 93 then: 53 elsif total <= difficulty
  110. 53 ResultLevel.new(:regular_success)
  111. else: 40 else
  112. 40 ResultLevel.new(:failure)
  113. end
  114. end
  115. 1 def initialize(level)
  116. 219 @level = level
  117. 219 @level_index = LEVEL.index(level)
  118. 219 else: 219 then: 0 raise ArgumentError unless @level_index
  119. end
  120. 1 def success?
  121. 87 @level_index >= LEVEL.index(:success)
  122. end
  123. 1 def failure?
  124. 16 @level_index <= LEVEL.index(:failure)
  125. end
  126. 1 def critical?
  127. 41 @level == :critical
  128. end
  129. 1 def fumble?
  130. 41 @level == :fumble
  131. end
  132. 1 def to_s
  133. 219 LEVEL_TO_S[@level]
  134. end
  135. end
  136. 1 private
  137. 1 include Rollable
  138. 1 def roll_1d8_table(table_name, table)
  139. 6 total_n = @randomizer.roll_once(8)
  140. 6 index = total_n - 1
  141. 6 text = table[index]
  142. 6 return "#{table_name}(#{total_n}) > #{text}"
  143. end
  144. 1 def roll_1d100_table(table_name, table)
  145. 6 total_n = @randomizer.roll_once(100)
  146. 6 index = total_n - 1
  147. 6 text = table[index]
  148. 6 return "#{table_name}(#{total_n}) > #{text}"
  149. end
  150. 1 def skill_roll(command)
  151. 50 m = /^CC([-+]?\d+)?(?:<=(\d+)([RHEC])?)?$/.match(command)
  152. 50 else: 50 then: 0 unless m
  153. return nil
  154. end
  155. 50 bonus_dice = m[1].to_i
  156. 50 then: 45 else: 5 difficulty = m[2]&.to_i
  157. 50 difficulty_level = m[3]
  158. 50 then: 2 if difficulty == 0
  159. 2 else: 48 difficulty = nil
  160. 48 then: 4 elsif difficulty_level == "H"
  161. 4 else: 44 difficulty /= 2
  162. 44 then: 3 elsif difficulty_level == "E"
  163. 3 else: 41 difficulty /= 5
  164. 41 then: 3 else: 38 elsif difficulty_level == "C"
  165. 3 difficulty = 0
  166. end
  167. 50 then: 2 else: 48 if bonus_dice == 0 && difficulty.nil?
  168. 2 dice = @randomizer.roll_once(100)
  169. 2 return "1D100 > #{dice}"
  170. end
  171. 48 then: 2 else: 46 if bonus_dice.abs > 100
  172. 2 return "請將獎勵・懲罰骰的數量設置在-100以上及100以下"
  173. end
  174. 46 total, total_list = roll_with_bonus(bonus_dice)
  175. 46 then: 5 else: 41 expr = difficulty.nil? ? "1D100" : "1D100<=#{difficulty}"
  176. result =
  177. 46 then: 15 if difficulty_level
  178. 15 else: 31 ResultLevel.with_difficulty_level(total, difficulty)
  179. 31 then: 26 else: 5 elsif difficulty
  180. 26 ResultLevel.from_values(total, difficulty)
  181. end
  182. sequence = [
  183. 46 "(#{expr}) 獎勵・懲罰骰[#{bonus_dice}]",
  184. total_list.join(", "),
  185. total,
  186. result,
  187. ].compact
  188. 46 Result.new.tap do |r|
  189. 46 r.text = sequence.join(" > ")
  190. 46 then: 41 else: 5 if result
  191. 41 r.condition = result.success?
  192. 41 r.critical = result.critical?
  193. 41 r.fumble = result.fumble?
  194. end
  195. end
  196. end
  197. 1 def getFullAutoResult(command)
  198. 75 FullAuto.eval(command, @randomizer)
  199. end
  200. 1 def combine_roll(command)
  201. 12 m = /^CBR\((\d+),(\d+)\)$/.match(command)
  202. 12 else: 11 then: 1 return nil unless m
  203. 11 difficulty_1 = m[1].to_i
  204. 11 difficulty_2 = m[2].to_i
  205. 11 total = @randomizer.roll_once(100)
  206. 11 result_1 = ResultLevel.from_values(total, difficulty_1)
  207. 11 result_2 = ResultLevel.from_values(total, difficulty_2)
  208. rank =
  209. 11 then: 4 if result_1.success? && result_2.success?
  210. 4 else: 7 "成功"
  211. 7 then: 5 elsif result_1.success? || result_2.success?
  212. 5 "部分成功"
  213. else: 2 else
  214. 2 "失敗"
  215. end
  216. 11 Result.new.tap do |r|
  217. 11 r.text = "(1d100<=#{difficulty_1},#{difficulty_2}) > #{total}[#{result_1},#{result_2}] > #{rank}"
  218. 11 r.success = result_1.success? && result_2.success?
  219. 11 r.failure = result_1.failure? && result_2.failure?
  220. end
  221. end
  222. # 表一式
  223. # 即時の恐懼症表
  224. 1 def roll_CCRT_table()
  225. 1 total_n = @randomizer.roll_once(10)
  226. 1 text = MADNESS_REAL_TIME_TABLE[total_n - 1]
  227. 1 time_n = @randomizer.roll_once(10)
  228. 1 return "瘋狂發作(即時型)(#{total_n}) > #{text}(1D10>#{time_n}回合)"
  229. end
  230. 1 MADNESS_REAL_TIME_TABLE = [
  231. '失憶(Amnesia):調查員完全忘記了自上個安全地點以來的所有記憶。對他們而言,似乎上一刻還在享用早餐,下一瞬卻面對著可怕的怪物。',
  232. '假性殘疾(Psychosomatic Disability):調查員經歷著心理上的失明、失聰或肢體缺失感,陷入無法自救的困境。',
  233. '暴力傾向(Violence):調查員在一陣狂暴中失去理智,對周圍的敵人與友方展開毫不留情的攻擊。',
  234. '偏執(Paranoia):調查員經歷著嚴重的偏執妄想,他感覺到每個人都在暗中威脅他!沒有一個人可被信任!他被無形的目光監視;他將被背叛;所見的一切皆是詭計,萬事皆虛。',
  235. '人際依賴(Significant Person):守秘人細心檢視調查員背景中的重要人物條目。調查員誤將場景中的另一人視為其重要人物,並基於這種錯誤的認知行動。',
  236. '昏厥(Faint):調查員突然失去意識,陷入短暫的昏迷。',
  237. '逃避行為(Flee in Panic):調查員在極度恐慌中,無論如何都想逃離當前的境地,即使這意味著奪走唯一的交通工具且撇下他人。',
  238. '歇斯底里(Physical Hysterics or Emotional Outburst):調查員在情緒的漩渦中崩潰,表現出無法控制的大笑、哭泣或尖叫等極端情感。',
  239. '恐懼(Phobia):調查員突如其來地產生一種新的恐懼症,例如幽閉恐懼症、惡靈恐懼症或蟑螂恐懼症。即使恐懼的來源並不在場,他們在接下來的輪數中仍會想像其存在,所有行動都將受到懲罰骰的影響。',
  240. '狂躁(Mania):調查員獲得一種新的狂躁症,例如嚴重的潔癖強迫症、非理性的說謊強迫症或異常喜愛蠕蟲的強迫症。在接下來的輪數內,他們會不斷追求滿足這種狂躁,所有行動都將受到懲罰骰的影響。',
  241. ].freeze
  242. # 略式の恐怖表
  243. 1 def roll_CCSU_table()
  244. 1 total_n = @randomizer.roll_once(10)
  245. 1 text = MADNESS_SUMMARY_TABLE[total_n - 1]
  246. 1 time_n = @randomizer.roll_once(10)
  247. 1 return "狂氣發作(總結型)(#{total_n}) > #{text}(1D10>#{time_n}時間)"
  248. end
  249. 1 MADNESS_SUMMARY_TABLE = [
  250. '失憶(Amnesia):調查員回過神來,發現自己身處一個陌生的地方,完全忘記了自己的身份。記憶將隨著時間的推移逐漸恢復。',
  251. '被盜(Robbed):調查員在恢復意識後,驚覺自己身體無恙,卻遭到盜竊。如果他們攜帶了珍貴之物(見調查員背景),則需進行幸運檢定以決定是否被竊取。其他所有有價值的物品則自動消失。',
  252. '遍體鱗傷(Battered):調查員在醒來後,發現自己滿身是傷,傷痕纍累。生命值減少至瘋狂前的一半,但不會造成重傷。他們並未遭到盜竊,傷害的來源由守秘人決定。',
  253. '暴力傾向(Violence):調查員陷入一場強烈的暴力與破壞的狂潮。當他們回過神來時,可能會意識到自己所做的事情,也可能完全失去記憶。調查員施加暴力的對象,以及是否造成死亡或僅僅是傷害,均由守秘人決定。',
  254. '極端信念(Ideology/Beliefs):查看調查員背景中的思想與信念。調查員將以極端且瘋狂的方式表現出某種信念。例如,一位虔誠的信徒可能會在地鐵上高聲傳道。',
  255. '重要之人(Significant People):考慮調查員背景中對其至關重要的人物及其原因。在那1D10小時或更久的時間內,調查員曾不顧一切地接近那個人,並努力加深彼此的關係。',
  256. '被收容(Institutionalized):調查員在精神病院病房或警察局牢房中醒來,慢慢回想起導致自己被關押的經過。',
  257. '逃避行為(Flee in panic):調查員恢復意識時,發現自己身處遙遠的地方,可能迷失在荒野,或是在開往未知目的地的列車或長途巴士上。',
  258. '恐懼(Phobia):調查員突然獲得一種新的恐懼症。擲1D100以決定具體的恐懼症狀,或由守秘人選擇。調查員醒來後,會開始採取各種措施以避開恐懼的源頭。',
  259. '狂躁(Mania):調查員獲得一種新的狂躁症。在表中擲1D100以決定具體的狂躁症狀,或由守秘人選擇。在這次瘋狂的發作中,調查員將全然沉浸於新的狂躁症狀中。該症狀是否對他人可見則取決於守秘人和調查員。',
  260. ].freeze
  261. # キャスティング・ロールのプッシュに失敗した場合(小)
  262. 1 FAILED_CASTING_L_TABLE = [
  263. '視力模糊或暫時失明。',
  264. '殘缺不全的尖叫聲、聲音或其他噪音。',
  265. '強烈的風或其他大氣效應。',
  266. '流血——可能是由於施法者、在場其他人或環境(如牆壁)的出血。',
  267. '奇異的幻象和幻覺。',
  268. '周圍的小動物爆炸。',
  269. '異臭的硫磺味。',
  270. '不小心召喚了神話生物。',
  271. ].freeze
  272. # キャスティング・ロールのプッシュに失敗した場合(大)
  273. 1 FAILED_CASTING_M_TABLE = [
  274. '大地震動,牆壁破裂。',
  275. '巨大的雷電聲。',
  276. '血從天而降。',
  277. '施法者的手被乾枯和燒焦。',
  278. '施法者不正常地老化(年齡增加2D10歲,並應用特徵修正,請參見老化規則)。',
  279. '強大或眾多的神話生物出現,從施法者開始攻擊附近所有人!',
  280. '施法者或附近的所有人被吸到遙遠的時間或地方。',
  281. '不小心召喚了神話神明。',
  282. ].freeze
  283. # 恐懼症表
  284. 1 PHOBIAS_TABLE = [
  285. '洗澡恐懼症(Ablutophobia):對於洗滌或洗澡的恐懼。',
  286. '恐高症(Acrophobia):對於身處高處的恐懼。',
  287. '飛行恐懼症(Aerophobia):對飛行的恐懼。',
  288. '廣場恐懼症(Agoraphobia):對於開放的(擁擠)公共場所的恐懼。',
  289. '恐鶏症(Alektorophobia):對鶏的恐懼。',
  290. '大蒜恐懼症(Alliumphobia):對大蒜的恐懼。',
  291. '乘車恐懼症(Amaxophobia):對於乘坐地面載具的恐懼。',
  292. '恐風症(Ancraophobia):對風的恐懼。',
  293. '男性恐懼症(Androphobia):對於成年男性的恐懼。',
  294. '恐英症(Anglophobia):對英格蘭或英格蘭文化的恐懼。',
  295. '恐花症(Anthophobia):對花的恐懼。',
  296. '截肢者恐懼症(Apotemnophobia):對截肢者的恐懼。',
  297. '蜘蛛恐懼症(Arachnophobia):對蜘蛛的恐懼。',
  298. '閃電恐懼症(Astraphobia):對閃電的恐懼。',
  299. '廢墟恐懼症(Atephobia):對遺迹或殘址的恐懼。',
  300. '長笛恐懼症(Aulophobia):對長笛的恐懼。',
  301. '細菌恐懼症(Bacteriophobia):對細菌的恐懼。',
  302. '導彈/子彈恐懼症(Ballistophobia):對導彈或子彈的恐懼。',
  303. '跌落恐懼症(Basophobia):對於跌倒或摔落的恐懼。',
  304. '書籍恐懼症(Bibliophobia):對書籍的恐懼。',
  305. '植物恐懼症(Botanophobia):對植物的恐懼。',
  306. '美女恐懼症(Caligynephobia):對美貌女性的恐懼。',
  307. '寒冷恐懼症(Cheimaphobia):對寒冷的恐懼。',
  308. '恐鐘錶症(Chronomentrophobia):對於鐘錶的恐懼。',
  309. '幽閉恐懼症(Claustrophobia):對於處在封閉的空間中的恐懼。',
  310. '小丑恐懼症(Coulrophobia):對小丑的恐懼。',
  311. '恐犬症(Cynophobia):對狗的恐懼。',
  312. '惡魔恐懼症(Demonophobia):對邪靈或惡魔的恐懼。',
  313. '人群恐懼症(Demophobia):對人群的恐懼。',
  314. '牙科恐懼症①(Dentophobia):對牙醫的恐懼。',
  315. '丟弃恐懼症(Disposophobia):對於丟弃物件的恐懼(貯藏癖)。',
  316. '皮毛恐懼症(Doraphobia):對動物皮毛的恐懼。',
  317. '過馬路恐懼症(Dromophobia):對於過馬路的恐懼。',
  318. '教堂恐懼症(Ecclesiophobia):對教堂的恐懼。',
  319. '鏡子恐懼症(Eisoptrophobia):對鏡子的恐懼。',
  320. '針尖恐懼症(Enetophobia):對針或大頭針的恐懼。',
  321. '昆蟲恐懼症(Entomophobia):對昆蟲的恐懼。',
  322. '恐猫症(Felinophobia):對猫的恐懼。',
  323. '過橋恐懼症(Gephyrophobia):對於過橋的恐懼。',
  324. '恐老症(Gerontophobia):對於老年人或變老的恐懼。',
  325. '恐女症(Gynophobia):對女性的恐懼。',
  326. '恐血症(Haemaphobia):對血的恐懼。',
  327. '宗教罪行恐懼症(Hamartophobia):對宗教罪行的恐懼。',
  328. '觸摸恐懼症(Haphophobia):對於被觸摸的恐懼。',
  329. '爬蟲恐懼症(Herpetophobia):對爬行動物的恐懼。',
  330. '迷霧恐懼症(Homichlophobia):對霧的恐懼。',
  331. '火器恐懼症(Hoplophobia):對火器的恐懼。',
  332. '恐水症(Hydrophobia):對水的恐懼。',
  333. '催眠恐懼症①(Hypnophobia):對於睡眠或被催眠的恐懼。',
  334. '白袍恐懼症(Iatrophobia):對醫生的恐懼。',
  335. '魚類恐懼症(Ichthyophobia):對魚的恐懼。',
  336. '蟑螂恐懼症(Katsaridaphobia):對蟑螂的恐懼。',
  337. '雷鳴恐懼症(Keraunophobia):對雷聲的恐懼。',
  338. '蔬菜恐懼症(Lachanophobia):對蔬菜的恐懼。',
  339. '噪音恐懼症(Ligyrophobia):對刺耳噪音的恐懼。',
  340. '恐湖症(Limnophobia):對湖泊的恐懼。',
  341. '機械恐懼症(Mechanophobia):對機器或機械的恐懼。',
  342. '巨物恐懼症(Megalophobia):對於龐大物件的恐懼。',
  343. '捆綁恐懼症(Merinthophobia):對於被捆綁或緊縛的恐懼。',
  344. '流星恐懼症(Meteorophobia):對流星或隕石的恐懼。',
  345. '孤獨恐懼症(Monophobia):對於一人獨處的恐懼。',
  346. '不潔恐懼症(Mysophobia):對污垢或污染的恐懼。',
  347. '粘液恐懼症(Myxophobia):對粘液(史萊姆)的恐懼。',
  348. '屍體恐懼症(Necrophobia):對屍體的恐懼。',
  349. '數字8恐懼症(Octophobia):對數字8的恐懼。',
  350. '恐牙症(Odontophobia):對牙齒的恐懼。',
  351. '恐夢症(Oneirophobia):對夢境的恐懼。',
  352. '稱呼恐懼症(Onomatophobia):對於特定詞語的恐懼。',
  353. '恐蛇症(Ophidiophobia):對蛇的恐懼。',
  354. '恐鳥症(Ornithophobia):對鳥的恐懼。',
  355. '寄生蟲恐懼症(Parasitophobia):對寄生蟲的恐懼。',
  356. '人偶恐懼症(Pediophobia):對人偶的恐懼。',
  357. '吞咽恐懼症(Phagophobia):對於吞咽或被吞咽的恐懼。',
  358. '藥物恐懼症(Pharmacophobia):對藥物的恐懼。',
  359. '幽靈恐懼症(Phasmophobia):對鬼魂的恐懼。',
  360. '日光恐懼症(Phenogophobia):對日光的恐懼。',
  361. '鬍鬚恐懼症(Pogonophobia):對鬍鬚的恐懼。',
  362. '河流恐懼症(Potamophobia):對河流的恐懼。',
  363. '酒精恐懼症(Potophobia):對酒或酒精的恐懼。',
  364. '恐火症(Pyrophobia):對火的恐懼。',
  365. '魔法恐懼症(Rhabdophobia):對魔法的恐懼。',
  366. '黑暗恐懼症(Scotophobia):對黑暗或夜晚的恐懼。',
  367. '恐月症(Selenophobia):對月亮的恐懼。',
  368. '火車恐懼症(Siderodromophobia):對於乘坐火車出行的恐懼。',
  369. '恐星症(Siderophobia):對星星的恐懼。',
  370. '狹室恐懼症(Stenophobia):對狹小物件或地點的恐懼。',
  371. '對稱恐懼症(Symmetrophobia):對對稱的恐懼。',
  372. '活埋恐懼症(Taphephobia):對於被活埋或墓地的恐懼。',
  373. '公牛恐懼症(Taurophobia):對公牛的恐懼。',
  374. '電話恐懼症(Telephonophobia):對電話的恐懼。',
  375. '怪物恐懼症①(Teratophobia):對怪物的恐懼。',
  376. '深海恐懼症(Thalassophobia):對海洋的恐懼。',
  377. '手術恐懼症(Tomophobia):對外科手術的恐懼。',
  378. '十三恐懼症(Triskadekaphobia):對數字13的恐懼症。',
  379. '衣物恐懼症(Vestiphobia):對衣物的恐懼。',
  380. '女巫恐懼症(Wiccaphobia):對女巫與巫術的恐懼。',
  381. '黃色恐懼症(Xanthophobia):對黃色或「黃」字的恐懼。',
  382. '外語恐懼症(Xenoglossophobia):對外語的恐懼。',
  383. '异域恐懼症(Xenophobia):對陌生人或外國人的恐懼。',
  384. '動物恐懼症(Zoophobia):對動物的恐懼。',
  385. ].freeze
  386. # 狂熱症表
  387. 1 MANIAS_TABLE = [
  388. '沐浴癖(Ablutomania):執著於清洗自己。',
  389. '猶豫癖(Aboulomania):病態地猶豫不定。',
  390. '喜暗狂(Achluomania):對黑暗的過度熱愛。',
  391. '喜高狂(Acromaniaheights):狂熱迷戀高處。',
  392. '親切癖(Agathomania):病態地對他人友好。',
  393. '喜曠症(Agromania):强烈地傾向於待在開闊空間中。',
  394. '喜尖狂(Aichmomania):痴迷於尖銳或鋒利的物體。',
  395. '戀猫狂(Ailuromania):近乎病態地對猫友善。',
  396. '疼痛癖(Algomania):痴迷於疼痛。',
  397. '喜蒜狂(Alliomania):痴迷於大蒜。',
  398. '乘車癖(Amaxomania):痴迷於乘坐車輛。',
  399. '欣快癖(Amenomania):不正常地感到喜悅。',
  400. '喜花狂(Anthomania):痴迷於花朵。',
  401. '計算癖(Arithmomania):狂熱地痴迷於數字。',
  402. '消費癖(Asoticamania):魯莽衝動地消費。',
  403. '隱居癖(Eremiomania):過度地熱愛獨自隱居。',
  404. '芭蕾癖(Balletmania):痴迷於芭蕾舞。',
  405. '竊書癖(Biliokleptomania):無法克制偷竊書籍的衝動。',
  406. '戀書狂(Bibliomania):痴迷於書籍和/或閱讀',
  407. '磨牙癖(Bruxomania):無法克制磨牙的衝動。',
  408. '靈臆症(Cacodemomania):病態地堅信自己已被一個邪惡的靈體占據。',
  409. '美貌狂(Callomania):痴迷於自身的美貌。',
  410. '地圖狂(Cartacoethes):在何時何處都無法控制查閱地圖的衝動。',
  411. '跳躍狂(Catapedamania):痴迷於從高處跳下。',
  412. '喜冷症(Cheimatomania):對寒冷或寒冷的物體的反常喜愛。',
  413. '舞蹈狂(Choreomania):無法控制地起舞或發顫。',
  414. '戀床癖(Clinomania):過度地熱愛待在床上。',
  415. '戀墓狂(Coimetormania):痴迷於墓地。',
  416. '色彩狂(Coloromania):痴迷於某種顔色。',
  417. '小丑狂(Coulromania):痴迷於小丑。',
  418. '恐懼狂(Countermania):執著於經歷恐怖的場面。',
  419. '殺戮癖(Dacnomania):痴迷於殺戮。',
  420. '魔臆症(Demonomania):病態地堅信自己已被惡魔附身。',
  421. '抓撓癖(Dermatillomania):執著於抓撓自己的皮膚。',
  422. '正義狂(Dikemania):痴迷於目睹正義被伸張。',
  423. '嗜酒狂(Dipsomania):反常地渴求酒精。',
  424. '毛皮狂(Doramania):痴迷於擁有毛皮。',
  425. '贈物癖(Doromania):痴迷於贈送禮物。',
  426. '漂泊症(Drapetomania):執著於逃離。',
  427. '漫游癖(Ecdemiomania):執著於四處漫游。',
  428. '自戀狂(Egomania):近乎病態地以自我爲中心或自我崇拜。',
  429. '職業狂(Empleomania):對於工作的無盡病態渴求。',
  430. '臆罪症(Enosimania):病態地堅信自己帶有罪孽。',
  431. '學識狂(Epistemomania):痴迷於獲取學識。',
  432. '靜止癖(Eremiomania):執著於保持安靜。',
  433. '乙醚上癮(Etheromania):渴求乙醚。',
  434. '求婚狂(Gamomania):痴迷於進行奇特的求婚。',
  435. '狂笑癖(Geliomania):無法自製地,强迫性的大笑。',
  436. '巫術狂(Goetomania):痴迷於女巫與巫術。',
  437. '寫作癖(Graphomania):痴迷於將每一件事寫下來。',
  438. '裸體狂(Gymnomania):執著於裸露身體。',
  439. '妄想狂(Habromania):近乎病態地充滿愉快的妄想(而不顧現實狀况如何)。',
  440. '蠕蟲狂(Helminthomania):過度地喜愛蠕蟲。',
  441. '槍械狂(Hoplomania):痴迷於火器。',
  442. '飲水狂(Hydromania):反常地渴求水分。',
  443. '喜魚癖(Ichthyomania):痴迷於魚類。',
  444. '圖標狂(Iconomania):痴迷於圖標與肖像',
  445. '偶像狂(Idolomania):痴迷於甚至願獻身於某個偶像。',
  446. '信息狂(Infomania):痴迷於積累各種信息與資訊。',
  447. '射擊狂(Klazomania):反常地執著於射擊。',
  448. '偷竊癖(Kleptomania):反常地執著於偷竊。',
  449. '噪音癖(Ligyromania):無法自製地執著於製造響亮或刺耳的噪音。',
  450. '喜綫癖(Linonomania):痴迷於綫繩。',
  451. '彩票狂(Lotterymania):極端地執著於購買彩票。',
  452. '抑鬱症(Lypemania):近乎病態的重度抑鬱傾向。',
  453. '巨石狂(Megalithomania):當站在石環中或立起的巨石旁時,就會近乎病態地寫出各種奇怪的創意。',
  454. '旋律狂(Melomania):痴迷於音樂或一段特定的旋律。',
  455. '作詩癖(Metromania):無法抑制地想要不停作詩。',
  456. '憎恨癖(Misomania):憎恨一切事物,痴迷於憎恨某個事物或團體。',
  457. '偏執狂(Monomania):近乎病態地痴迷與專注某個特定的想法或創意。',
  458. '誇大癖(Mythomania):以一種近乎病態的程度說謊或誇大事物。',
  459. '臆想症(Nosomania):妄想自己正在被某種臆想出的疾病折磨。',
  460. '記錄癖(Notomania):執著於記錄一切事物(例如攝影)',
  461. '戀名狂(Onomamania):痴迷於名字(人物的、地點的、事物的)',
  462. '稱名癖(Onomatomania):無法抑制地不斷重複某個詞語的衝動。',
  463. '剔指癖(Onychotillomania):執著於剔指甲。',
  464. '戀食癖(Opsomania):對某種食物的病態熱愛。',
  465. '抱怨癖(Paramania):一種在抱怨時産生的近乎病態的愉悅感。',
  466. '面具狂(Personamania):執著於佩戴面具。',
  467. '幽靈狂(Phasmomania):痴迷於幽靈。',
  468. '謀殺癖(Phonomania):病態的謀殺傾向。',
  469. '渴光癖(Photomania):對光的病態渴求。',
  470. '背德癖(ASPD):病態地渴求違背社會道德。',
  471. '求財癖(Plutomania):對財富的强迫性的渴望。',
  472. '欺騙狂(Pseudomania):無法抑制的執著於撒謊。',
  473. '縱火狂(Pyromania):執著於縱火。',
  474. '提問狂(Questiong-Asking Mania):執著於提問。',
  475. '挖鼻癖(Rhinotillexomania):執著於挖鼻子。',
  476. '塗鴉癖(Scribbleomania):沉迷於塗鴉。',
  477. '列車狂(Siderodromomania):認爲火車或類似的依靠軌道交通的旅行方式充滿魅力。',
  478. '臆智症(Sophomania):臆想自己擁有難以置信的智慧。',
  479. '科技狂(Technomania):痴迷於新的科技。',
  480. '臆咒狂(Thanatomania):堅信自己已被某種死亡魔法所詛咒。',
  481. '臆神狂(Theomania):堅信自己是一位神靈。',
  482. '抓撓癖(Titillomaniac):抓撓自己的强迫傾向。',
  483. '手術狂(Tomomania):對進行手術的不正常愛好。',
  484. '拔毛癖(Trichotillomania):執著於拔下自己的頭髮。',
  485. '臆盲症(Typhlomania):病理性的失明。',
  486. '嗜外狂(Xenomania):痴迷於异國的事物。',
  487. '喜獸癖(Zoomania):對待動物的態度近乎瘋狂地友好。',
  488. ].freeze
  489. end
  490. end
  491. end

lib/bcdice/game_system/Cthulhu7th_ChineseTraditional/full_auto.rb

99.32% lines covered

95.0% branches covered

148 relevant lines. 147 lines covered and 1 lines missed.
60 total branches, 57 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Cthulhu7th_ChineseTraditional < Base
  5. 1 class FullAuto
  6. 1 BONUS_DICE_RANGE = (-2..2).freeze
  7. # 停止連射的條件(難度閾值)
  8. # @return [Hash<String, Integer>]
  9. #
  10. # 成功類型的小寫表記 => 難度的閾值
  11. 1 ROLL_FULL_AUTO_DIFFICULTY_THRESHOLD = {
  12. # 一般
  13. "r" => 0,
  14. # 困難
  15. "h" => 1,
  16. # 極限
  17. "e" => 2
  18. }.freeze
  19. 1 def self.eval(command, randomizer)
  20. 75 new.eval(command, randomizer)
  21. end
  22. 1 def eval(command, randomizer)
  23. 75 @randomizer = randomizer
  24. 75 get_full_auto_result(command)
  25. end
  26. 1 private
  27. 1 include Rollable
  28. 1 def get_full_auto_result(command)
  29. 75 m = /^FAR\((-?\d+),(-?\d+),(-?\d+)(?:,(-?\d+)?)?(?:,(-?\w+)?)?(?:,(-?\d+)?)?\)$/i.match(command)
  30. 75 else: 75 then: 0 unless m
  31. return nil
  32. end
  33. 75 bullet_count = m[1].to_i
  34. 75 diff = m[2].to_i
  35. 75 broken_number = m[3].to_i
  36. 75 bonus_dice_count = m[4].to_i
  37. 75 then: 24 else: 51 stop_count = m[5]&.downcase || ""
  38. 75 then: 20 else: 55 bullet_set_count_cap = m[6]&.to_i || diff / 10
  39. 75 output = ""
  40. # 最大(8次 * (PC技能值最大值 / 10))= 72發,因此設置上限
  41. 75 bullet_count_limit = 100
  42. 75 then: 2 else: 73 if bullet_count > bullet_count_limit
  43. 2 output += "彈藥數量過多。將裝填的彈藥數量更改為#{bullet_count_limit}發。\n"
  44. 2 bullet_count = bullet_count_limit
  45. end
  46. # 如果設置的連射上限不合理則顯示注意
  47. 75 then: 2 if (bullet_set_count_cap > diff / 10) && (diff > 39) && !m[6].nil?
  48. 2 bullet_set_count_cap = diff / 10
  49. 2 else: 73 output += "連射的彈藥數量上限為\[技能值÷10(取整)\]發,因此無法指定更高的數量。連射的彈藥數量更改為#{bullet_set_count_cap}發。\n"
  50. 73 then: 2 else: 71 elsif (diff <= 39) && (bullet_set_count_cap > 3) && !m[6].nil?
  51. 2 bullet_set_count_cap = 3
  52. 2 output += "技能值在39以下時,連射的彈藥數量上限和下限均為3發。連射的彈藥數量更改為#{bullet_set_count_cap}發。\n"
  53. end
  54. # 如果設置的連射下限不合理則顯示注意或錯誤
  55. 75 then: 2 else: 73 return "連射的彈藥數量必須為正數。" if (bullet_set_count_cap <= 0) && !m[6].nil?
  56. 73 then: 5 else: 68 if (bullet_set_count_cap < 3) && !m[6].nil?
  57. 5 bullet_set_count_cap = 3
  58. 5 output += "連射的彈藥數量下限為3發。連射的彈藥數量更改為3發。\n"
  59. end
  60. 73 then: 2 else: 71 return "彈藥數量必須為正數。" if bullet_count <= 0
  61. 71 then: 1 else: 70 return "目標值必須為正數。" if diff <= 0
  62. 70 then: 1 else: 69 if broken_number < 0
  63. 1 output += "故障值必須為正數。去掉負號。\n"
  64. 1 broken_number = broken_number.abs
  65. end
  66. 70 else: 68 then: 2 unless BONUS_DICE_RANGE.include?(bonus_dice_count)
  67. 2 return "錯誤。獎勵・懲罰骰的值必須在#{BONUS_DICE_RANGE.min}~#{BONUS_DICE_RANGE.max}之間。"
  68. end
  69. 68 output += "獎勵・懲罰骰[#{bonus_dice_count}]"
  70. 68 output += roll_full_auto(bullet_count, diff, broken_number, bonus_dice_count, stop_count, bullet_set_count_cap)
  71. 68 return output
  72. end
  73. 1 def roll_full_auto(bullet_count, diff, broken_number, dice_num, stop_count, bullet_set_count_cap)
  74. 68 output = ""
  75. 68 loop_count = 0
  76. 68 counts = {
  77. hit_bullet: 0,
  78. impale_bullet: 0,
  79. bullet: bullet_count,
  80. }
  81. # 難度變更用循環
  82. 68 4.times do |more_difficulty|
  83. 89 output += get_next_difficulty_message(more_difficulty)
  84. # 隨著懲罰骰的減少進行擲骰循環
  85. 89 body: 156 while dice_num >= BONUS_DICE_RANGE.min
  86. 156 loop_count += 1
  87. 156 hit_result, total, total_list = get_hit_result_infos(dice_num, diff, more_difficulty)
  88. 156 output += "\n#{loop_count}次: > #{total_list.join(', ')} > #{hit_result}"
  89. 156 then: 27 else: 129 if total >= broken_number
  90. 27 output += " 卡彈"
  91. 27 return get_hit_result_text(output, counts)
  92. end
  93. 129 hit_type = get_hit_type(more_difficulty, hit_result)
  94. 129 hit_bullet, impale_bullet, lost_bullet = get_bullet_results(counts[:bullet], hit_type, diff, bullet_set_count_cap)
  95. 129 output += " (#{hit_bullet}發命中,#{impale_bullet}發貫穿)"
  96. 129 counts[:hit_bullet] += hit_bullet
  97. 129 counts[:impale_bullet] += impale_bullet
  98. 129 counts[:bullet] -= lost_bullet
  99. 129 then: 24 else: 105 return get_hit_result_text(output, counts) if counts[:bullet] <= 0
  100. 105 dice_num -= 1
  101. end
  102. # 當達到指定的難度時,停止連射處理
  103. 38 then: 14 else: 24 if should_stop_roll_full_auto?(stop_count, more_difficulty)
  104. 14 output += "\n【因達到指定難度,處理結束。】"
  105. 14 break
  106. end
  107. 24 dice_num += 1
  108. end
  109. 17 return get_hit_result_text(output, counts)
  110. end
  111. # 判斷是否應該停止連射處理
  112. # @param [String] stop_count 成功的類型
  113. # @param [Integer] difficulty 難度
  114. # @return [Boolean]
  115. 1 def should_stop_roll_full_auto?(stop_count, difficulty)
  116. 38 difficulty_threshold = ROLL_FULL_AUTO_DIFFICULTY_THRESHOLD[stop_count]
  117. 38 return difficulty_threshold && difficulty >= difficulty_threshold
  118. end
  119. 1 def get_hit_result_infos(dice_num, diff, more_difficulty)
  120. 156 total, total_list = roll_with_bonus(dice_num)
  121. 156 fumbleable = get_fumbleable(more_difficulty)
  122. 156 hit_result = ResultLevel.from_values(total, diff, fumbleable).to_s
  123. 156 return hit_result, total, total_list
  124. end
  125. 1 def get_hit_result_text(output, counts)
  126. 68 return "#{output}\n> #{counts[:hit_bullet]}發一般命中,#{counts[:impale_bullet]}發貫穿,剩餘彈藥#{counts[:bullet]}發"
  127. end
  128. 1 def get_hit_type(more_difficulty, hit_result)
  129. 129 success_list, impale_bullet_list = get_success_list_impale_bullet_list(more_difficulty)
  130. 129 then: 54 else: 75 return :hit if success_list.include?(hit_result)
  131. 75 then: 38 else: 37 return :impale if impale_bullet_list.include?(hit_result)
  132. 37 return ""
  133. end
  134. 1 def get_bullet_results(bullet_count, hit_type, diff, bullet_set_count_cap)
  135. 129 bullet_set_count = get_set_of_bullet(diff, bullet_set_count_cap)
  136. 129 hit_bullet_count_base = get_hit_bullet_count_base(diff, bullet_set_count)
  137. 129 impale_bullet_count_base = (bullet_set_count / 2.to_f)
  138. 129 lost_bullet_count = 0
  139. 129 hit_bullet_count = 0
  140. 129 impale_bullet_count = 0
  141. 129 if !last_bullet_turn?(bullet_count, bullet_set_count)
  142. then: 115
  143. 115 else: 37 case hit_type
  144. when: 45 when :hit
  145. 45 hit_bullet_count = hit_bullet_count_base # 計算一般命中的彈數
  146. when: 33 when :impale
  147. 33 impale_bullet_count = impale_bullet_count_base.floor # 計算貫穿的彈數
  148. 33 hit_bullet_count = impale_bullet_count_base.ceil
  149. end
  150. 115 lost_bullet_count = bullet_set_count
  151. else
  152. else: 14
  153. 14 else: 0 case hit_type
  154. when: 9 when :hit
  155. 9 hit_bullet_count = get_last_hit_bullet_count(bullet_count)
  156. when: 5 when :impale
  157. 5 impale_bullet_count = get_last_hit_bullet_count(bullet_count)
  158. 5 hit_bullet_count = bullet_count - impale_bullet_count
  159. end
  160. 14 lost_bullet_count = bullet_count
  161. end
  162. 129 return hit_bullet_count, impale_bullet_count, lost_bullet_count
  163. end
  164. 1 def get_success_list_impale_bullet_list(more_difficulty)
  165. 129 success_list = []
  166. 129 impale_bullet_list = []
  167. 129 else: 0 case more_difficulty
  168. when: 116 when 0
  169. 116 success_list = ["困難成功", "一般成功"]
  170. 116 impale_bullet_list = ["大成功", "極限成功"]
  171. when: 6 when 1
  172. 6 success_list = ["困難成功"]
  173. 6 impale_bullet_list = ["大成功", "極限成功"]
  174. when: 4 when 2
  175. 4 success_list = []
  176. 4 impale_bullet_list = ["大成功", "極限成功"]
  177. when: 3 when 3
  178. 3 success_list = ["大成功"]
  179. 3 impale_bullet_list = []
  180. end
  181. 129 return success_list, impale_bullet_list
  182. end
  183. 1 def get_next_difficulty_message(more_difficulty)
  184. 89 else: 68 case more_difficulty
  185. when: 13 when 1
  186. 13 return "\n【難度已更改為困難】"
  187. when: 5 when 2
  188. 5 return "\n【難度已更改為極限】"
  189. when: 3 when 3
  190. 3 return "\n【難度已更改為大成功】"
  191. end
  192. 68 return ""
  193. end
  194. 1 def get_set_of_bullet(diff, bullet_set_count_cap)
  195. 129 bullet_set_count = diff / 10
  196. 129 then: 9 else: 120 if bullet_set_count_cap < bullet_set_count
  197. 9 bullet_set_count = bullet_set_count_cap
  198. end
  199. 129 then: 21 else: 108 if (diff >= 1) && (diff < 30)
  200. 21 bullet_set_count = 3 # 技能值在29以下的最低值保障處理
  201. end
  202. 129 return bullet_set_count
  203. end
  204. 1 def get_hit_bullet_count_base(diff, bullet_set_count)
  205. 129 hit_bullet_count_base = (bullet_set_count / 2)
  206. 129 then: 21 else: 108 if (diff >= 1) && (diff < 30)
  207. 21 hit_bullet_count_base = 1 # 技能值在29以下的最低值保障
  208. end
  209. 129 return hit_bullet_count_base
  210. end
  211. 1 def last_bullet_turn?(bullet_count, bullet_set_count)
  212. 129 ((bullet_count - bullet_set_count) < 0)
  213. end
  214. 1 def get_last_hit_bullet_count(bullet_count)
  215. # 剩餘1發的最低值保障處理
  216. 14 then: 5 else: 9 if bullet_count == 1
  217. 5 return 1
  218. end
  219. 9 count = (bullet_count / 2.to_f).floor
  220. 9 return count
  221. end
  222. 1 def get_fumbleable(more_difficulty)
  223. # 因為成功的出目必須在49以下,因此失誤值上升
  224. 156 return (more_difficulty >= 1)
  225. end
  226. end
  227. end
  228. end
  229. end

lib/bcdice/game_system/Cthulhu7th_ChineseTraditional/rollable.rb

100.0% lines covered

100.0% branches covered

19 relevant lines. 19 lines covered and 0 lines missed.
6 total branches, 6 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Cthulhu7th_ChineseTraditional < Base
  5. 1 module Rollable
  6. 1 private
  7. # 1D100の一の位用のダイスロール
  8. # 0から9までの値を返す
  9. #
  10. # @return [Integer]
  11. 1 def roll_ones_d10
  12. 202 dice = @randomizer.roll_once(10)
  13. 202 then: 27 else: 175 return 0 if dice == 10
  14. 175 return dice
  15. end
  16. # @param bonus [Integer] ボーナス・ペナルティダイスの数。負の数ならペナルティダイス。
  17. # @return [Array<(Integer, Array<Integer>)>]
  18. 1 def roll_with_bonus(bonus)
  19. 604 tens_list = Array.new(bonus.abs + 1) { @randomizer.roll_tens_d10 }
  20. 202 ones = roll_ones_d10()
  21. 202 dice_list = tens_list.map do |tens|
  22. 402 dice = tens + ones
  23. 402 then: 24 else: 378 dice == 0 ? 100 : dice
  24. end
  25. dice =
  26. 202 then: 101 if bonus >= 0
  27. 101 dice_list.min
  28. else: 101 else
  29. 101 dice_list.max
  30. end
  31. 202 return dice, dice_list
  32. end
  33. end
  34. end
  35. end
  36. end

lib/bcdice/game_system/Cthulhu7th_Korean.rb

99.49% lines covered

94.19% branches covered

195 relevant lines. 194 lines covered and 1 lines missed.
86 total branches, 81 branches covered and 5 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Cthulhu7th_Korean < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Cthulhu7th:Korean'
  7. # ゲームシステム名
  8. 1 NAME = '크툴루의 부름 7판'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = '国際化:Korean:크툴루의 부름 7판'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・판정 CC(x)<=(목표치)
  14.  x:보너스, 패널티 주사위:Bonus/Penalty Dice (2~-2). 생략 가능.
  15.  대실패:Fumble/실패:Failure/보통 성공:Regular success/
  16.  어려운 성공:Hard success/대단한 성공:Extreme success/
  17.  대성공:Critical success 을 자동판정.
  18. 예)CC<=30 CC(2)<=50 CC(-1)<=75
  19. ・조합 판정 (CBR(x,y))
  20.  목표치 x 와 y 로 동시에 %판정을 한다.
  21.  예)CBR(50,20)
  22. ・연사(Full Auto)판정 FAR(w,x,y,z)
  23.  w:탄수(1~100), x:기능 수치(1~100), y:고장 넘버
  24.  z:보너스, 패널티 주사위(-2~2). 생략 가능.
  25.  명중수와 관통수, 잔탄수만을 계산. 데미지는 계산하지 않습니다.
  26. 예)FAR(25,70,98) FAR(50,80,98,-1)
  27. INFO_MESSAGE_TEXT
  28. 1 register_prefix('CC', 'CBR', 'FAR')
  29. 1 def initialize(command)
  30. 69 super(command)
  31. 69 @bonus_dice_range = (-2..2)
  32. end
  33. 1 def eval_game_system_specific_command(command)
  34. 69 else: 0 case command
  35. when: 23 when /CC/i
  36. 23 return getCheckResult(command)
  37. when: 11 when /CBR/i
  38. 11 return getCombineRoll(command)
  39. when: 35 when /FAR/i
  40. 35 return getFullAutoResult(command)
  41. end
  42. return nil
  43. end
  44. 1 def getCheckResult(command)
  45. 23 else: 23 then: 0 nil unless /^CC([-\d]+)?<=(\d+)/i =~ command
  46. 23 bonus_dice_count = Regexp.last_match(1).to_i # 보너스, 패널티 주사위의 개수
  47. 23 diff = Regexp.last_match(2).to_i
  48. 23 then: 1 else: 22 return "에러. 목표치는 1 이상입니다." if diff <= 0
  49. 22 else: 20 then: 2 unless @bonus_dice_range.include?(bonus_dice_count)
  50. 2 return "에러. 보너스, 패널티 주사위의 수치는 #{@bonus_dice_range.min}~#{@bonus_dice_range.max}입니다."
  51. end
  52. 20 output = ""
  53. 20 output += "(1D100<=#{diff})"
  54. 20 output += " 보너스, 패널티 주사위[#{bonus_dice_count}]"
  55. 20 units_digit = rollPercentD10
  56. 20 total_list = getTotalLists(bonus_dice_count, units_digit)
  57. 20 total = getTotal(total_list, bonus_dice_count)
  58. 20 result_text = getCheckResultText(total, diff)
  59. 20 output += " > #{total_list.join(', ')} > #{total} > #{result_text}"
  60. 20 return output
  61. end
  62. 1 def rollPercentD10
  63. 278 dice = @randomizer.roll_once(10)
  64. 278 then: 52 else: 226 dice = 0 if dice == 10
  65. 278 return dice
  66. end
  67. 1 def getTotalLists(bonus_dice_count, units_digit)
  68. 92 total_list = []
  69. 92 tens_digit_count = 1 + bonus_dice_count.abs
  70. 92 tens_digit_count.times do
  71. 186 bonus = rollPercentD10
  72. 186 total = (bonus * 10) + units_digit
  73. 186 then: 8 else: 178 total = 100 if total == 0
  74. 186 total_list.push(total)
  75. end
  76. 92 return total_list
  77. end
  78. 1 def getTotal(total_list, bonus_dice_count)
  79. 92 then: 48 else: 44 return total_list.min if bonus_dice_count >= 0
  80. 44 return total_list.max
  81. end
  82. 1 def getCheckResultText(total, diff, fumbleable = false)
  83. 112 then: 74 else: 38 if total <= diff
  84. 74 then: 9 else: 65 return "대성공" if total == 1
  85. 65 then: 15 else: 50 return "대단한 성공" if total <= (diff / 5)
  86. 50 then: 14 else: 36 return "어려운 성공" if total <= (diff / 2)
  87. 36 return "보통 성공"
  88. end
  89. 38 fumble_text = "대실패"
  90. 38 then: 7 else: 31 return fumble_text if total == 100
  91. 31 then: 15 else: 16 if total >= 96
  92. 15 then: 8 if diff < 50
  93. 8 return fumble_text
  94. else: 7 else
  95. 7 then: 4 else: 3 return fumble_text if fumbleable
  96. end
  97. end
  98. 19 return "실패"
  99. end
  100. 1 def getCombineRoll(command)
  101. 11 else: 10 then: 1 return nil unless /CBR\((\d+),(\d+)\)/i =~ command
  102. 10 diff_1 = Regexp.last_match(1).to_i
  103. 10 diff_2 = Regexp.last_match(2).to_i
  104. 10 total = @randomizer.roll_once(100)
  105. 10 result_1 = getCheckResultText(total, diff_1)
  106. 10 result_2 = getCheckResultText(total, diff_2)
  107. 10 successList = ["대성공", "대단한 성공", "어려운 성공", "보통성공"]
  108. 10 succesCount = 0
  109. 10 then: 5 else: 5 succesCount += 1 if successList.include?(result_1)
  110. 10 then: 4 else: 6 succesCount += 1 if successList.include?(result_2)
  111. 10 debug("succesCount", succesCount)
  112. rank =
  113. 10 then: 3 if succesCount >= 2
  114. 3 else: 7 "성공"
  115. 7 then: 3 elsif succesCount == 1
  116. 3 "부분적 성공"
  117. else: 4 else
  118. 4 "실패"
  119. end
  120. 10 return "(1d100<=#{diff_1},#{diff_2}) > #{total}[#{result_1},#{result_2}] > #{rank}"
  121. end
  122. 1 def getFullAutoResult(command)
  123. 35 else: 35 then: 0 return nil unless /^FAR\((-?\d+)(,(-?\d+))(,(-?\d+))(,(-?\d+))?\)/i =~ command
  124. 35 bullet_count = Regexp.last_match(1).to_i
  125. 35 diff = Regexp.last_match(3).to_i
  126. 35 broken_number = Regexp.last_match(5).to_i
  127. 35 bonus_dice_count = (Regexp.last_match(7) || 0).to_i
  128. 35 output = ""
  129. # 최대(8번*(PC기능 수치 최대값/10))=72발밖에 쏠 수 없으니 상한
  130. 35 bullet_count_limit = 100
  131. 35 then: 2 else: 33 if bullet_count > bullet_count_limit
  132. 2 output += "\n탄약이 너무 많습니다. 장전된 탄약을 #{bullet_count_limit}개로 변경합니다.\n"
  133. 2 bullet_count = bullet_count_limit
  134. end
  135. 35 then: 2 else: 33 return "탄약은 1 이상입니다." if bullet_count <= 0
  136. 33 then: 1 else: 32 return "목표치는 1 이상입니다." if diff <= 0
  137. 32 then: 1 else: 31 if broken_number < 0
  138. 1 output += "\n고장 넘버는 1 이상입니다. 마이너스 기호를 제거합니다.\n"
  139. 1 broken_number = broken_number.abs
  140. end
  141. 32 else: 30 then: 2 unless @bonus_dice_range.include?(bonus_dice_count)
  142. 2 return "\n에러. 보너스, 패널티 주사위의 수치는 #{@bonus_dice_range.min}~#{@bonus_dice_range.max}입니다."
  143. end
  144. 30 output += "보너스, 패널티 주사위 [#{bonus_dice_count}]"
  145. 30 output += rollFullAuto(bullet_count, diff, broken_number, bonus_dice_count)
  146. 30 return output
  147. end
  148. 1 def rollFullAuto(bullet_count, diff, broken_number, dice_num)
  149. 30 output = ""
  150. 30 loopCount = 0
  151. 30 counts = {
  152. hit_bullet: 0,
  153. impale_bullet: 0,
  154. bullet: bullet_count,
  155. }
  156. # 난이도 변경용 루프
  157. 30 4.times do |more_difficlty|
  158. 43 output += getNextDifficltyMessage(more_difficlty)
  159. # 패널티 다이스를 줄이면서 굴리는 용 루프
  160. 43 while dice_num >= @bonus_dice_range.min
  161. body: 72
  162. 72 loopCount += 1
  163. 72 hit_result, total, total_list = getHitResultInfos(dice_num, diff, more_difficlty)
  164. 72 output += "\n#{loopCount}번째: > #{total_list.join(', ')} > #{hit_result}"
  165. 72 then: 19 else: 53 if total >= broken_number
  166. 19 output += " 총알 걸림"
  167. 19 return getHitResultText(output, counts)
  168. end
  169. 53 hit_type = getHitType(more_difficlty, hit_result)
  170. 53 hit_bullet, impale_bullet, lost_bullet = getBulletResults(counts[:bullet], hit_type, diff)
  171. 53 counts[:hit_bullet] += hit_bullet
  172. 53 counts[:impale_bullet] += impale_bullet
  173. 53 counts[:bullet] -= lost_bullet
  174. 53 then: 8 else: 45 return getHitResultText(output, counts) if counts[:bullet] <= 0
  175. 45 dice_num -= 1
  176. end
  177. 16 dice_num += 1
  178. end
  179. 3 return getHitResultText(output, counts)
  180. end
  181. 1 def getHitResultInfos(dice_num, diff, more_difficlty)
  182. 72 units_digit = rollPercentD10
  183. 72 total_list = getTotalLists(dice_num, units_digit)
  184. 72 total = getTotal(total_list, dice_num)
  185. 72 fumbleable = getFumbleable(more_difficlty)
  186. 72 hit_result = getCheckResultText(total, diff, fumbleable)
  187. 72 return hit_result, total, total_list
  188. end
  189. 1 def getHitResultText(output, counts)
  190. 30 return "#{output}\n> #{counts[:hit_bullet]}발이 명중, #{counts[:impale_bullet]}발이 관통, 잔탄 #{counts[:bullet]}발"
  191. end
  192. 1 def getHitType(more_difficlty, hit_result)
  193. 53 successList, impaleBulletList = getSuccessListImpaleBulletList(more_difficlty)
  194. 53 then: 28 else: 25 return :hit if successList.include?(hit_result)
  195. 25 then: 11 else: 14 return :impale if impaleBulletList.include?(hit_result)
  196. 14 return ""
  197. end
  198. 1 def getBulletResults(bullet_count, hit_type, diff)
  199. 53 bullet_set_count = getSetOfBullet(diff)
  200. 53 hit_bullet_count_base = getHitBulletCountBase(diff, bullet_set_count)
  201. 53 impale_bullet_count_base = (bullet_set_count / 2.to_f)
  202. 53 lost_bullet_count = 0
  203. 53 hit_bullet_count = 0
  204. 53 impale_bullet_count = 0
  205. 53 if !isLastBulletTurn(bullet_count, bullet_set_count)
  206. then: 46
  207. 46 else: 14 case hit_type
  208. when: 24 when :hit
  209. 24 hit_bullet_count = hit_bullet_count_base # 보통명중한 탄수의 계산
  210. when: 8 when :impale
  211. 8 hit_bullet_count = impale_bullet_count_base.floor
  212. 8 impale_bullet_count = impale_bullet_count_base.ceil # 관통한 탄수의 계산
  213. end
  214. 46 lost_bullet_count = bullet_set_count
  215. else
  216. else: 7
  217. 7 else: 0 case hit_type
  218. when: 4 when :hit
  219. 4 hit_bullet_count = getLastHitBulletCount(bullet_count)
  220. when: 3 when :impale
  221. 3 halfbull = bullet_count / 2.to_f
  222. 3 hit_bullet_count = halfbull.floor
  223. 3 impale_bullet_count = halfbull.ceil
  224. end
  225. 7 lost_bullet_count = bullet_count
  226. end
  227. 53 return hit_bullet_count, impale_bullet_count, lost_bullet_count
  228. end
  229. 1 def getSuccessListImpaleBulletList(more_difficlty)
  230. 53 successList = []
  231. 53 impaleBulletList = []
  232. 53 else: 0 case more_difficlty
  233. when: 44 when 0
  234. 44 successList = ["어려운 성공", "보통 성공"]
  235. 44 impaleBulletList = ["대성공", "대단한 성공"]
  236. when: 3 when 1
  237. 3 successList = ["어려운 성공"]
  238. 3 impaleBulletList = ["대성공", "대단한 성공"]
  239. when: 3 when 2
  240. 3 successList = []
  241. 3 impaleBulletList = ["대성공", "대단한 성공"]
  242. when: 3 when 3
  243. 3 successList = ["대성공"]
  244. 3 impaleBulletList = []
  245. end
  246. 53 return successList, impaleBulletList
  247. end
  248. 1 def getNextDifficltyMessage(more_difficlty)
  249. 43 else: 30 case more_difficlty
  250. when: 7 when 1
  251. 7 return "\n 난이도가 어려운 성공으로 변경"
  252. when: 3 when 2
  253. 3 return "\n 난이도가 대단한 성공으로 변경"
  254. when: 3 when 3
  255. 3 return "\n 난이도가 대성공으로 변경"
  256. end
  257. 30 return ""
  258. end
  259. 1 def getSetOfBullet(diff)
  260. 53 bullet_set_count = diff / 10
  261. 53 then: 2 else: 51 if (diff >= 1) && (diff < 10)
  262. 2 bullet_set_count = 1 # 기능 수치가 9 이하일 때의 최저수치 보장 처리
  263. end
  264. 53 return bullet_set_count
  265. end
  266. 1 def getHitBulletCountBase(diff, bullet_set_count)
  267. 53 hit_bullet_count_base = (bullet_set_count / 2)
  268. 53 then: 2 else: 51 if (diff >= 1) && (diff < 10)
  269. 2 hit_bullet_count_base = 1 # 기능 수치가 9 이하일 때의 최저수치 보장
  270. end
  271. 53 return hit_bullet_count_base
  272. end
  273. 1 def isLastBulletTurn(bullet_count, bullet_set_count)
  274. 53 ((bullet_count - bullet_set_count) < 0)
  275. end
  276. 1 def getLastHitBulletCount(bullet_count)
  277. # 잔탄 1발일 때의 최저수치 보장 처리
  278. 4 then: 2 else: 2 if bullet_count == 1
  279. 2 return 1
  280. end
  281. 2 count = (bullet_count / 2.to_f).floor
  282. 2 return count
  283. end
  284. 1 def getFumbleable(more_difficlty)
  285. # 성공이 49 이하일때만이기 때문에 펌블치는 상승
  286. 72 return (more_difficlty >= 1)
  287. end
  288. end
  289. end
  290. end

lib/bcdice/game_system/CthulhuTech.rb

100.0% lines covered

86.36% branches covered

87 relevant lines. 87 lines covered and 0 lines missed.
22 total branches, 19 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/arithmetic_evaluator'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class CthulhuTech < Base
  6. 1 register_prefix('\d+D10')
  7. # ゲームシステムの識別子
  8. 1 ID = 'CthulhuTech'
  9. # ゲームシステム名
  10. 1 NAME = 'クトゥルフテック'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = 'くとうるふてつく'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  15. ・行為判定(test):nD10+m>=d
  16.  n個のダイスを使用して、修正値m、難易度dで行為判定(test)を行います。
  17.  修正値mは省略可能、複数指定可能(例:+2-4)です。
  18.  成功、失敗、クリティカル、ファンブルを自動判定します。
  19.  例)2D10>=12 4D10+2>=28 5D10+2-4>=32
  20. ・対抗判定(contest):nD10+m>d
  21.  行為判定と同様ですが、防御側有利のため「>=」ではなく「>」を入力します。
  22.  ダメージダイスも表示します。
  23. INFO_MESSAGE_TEXT
  24. # 行為判定のノード
  25. 1 class Test
  26. # 判定で用いる比較演算子
  27. #
  28. # 対抗判定で変えられるように定数で定義する。
  29. 1 COMPARE_OP = :>=
  30. # ノードを初期化する
  31. # @param [Integer] num ダイス数
  32. # @param [Integer] modifier 修正値
  33. # @param [Integer] difficulty 難易度
  34. 1 def initialize(num, modifier, difficulty)
  35. 68 @num = num
  36. 68 @modifier = modifier
  37. 68 @difficulty = difficulty
  38. end
  39. # 判定を行う
  40. # @param randomizer [Randoizer]
  41. # @return [String] 判定結果
  42. 1 def execute(randomizer)
  43. 68 dice_values = randomizer.roll_barabara(@num, 10)
  44. # ファンブル:出目の半分(小数点以下切り上げ)以上が1の場合
  45. 68 fumble = dice_values.count(1) >= (dice_values.length + 1) / 2
  46. 68 sorted_dice_values = dice_values.sort
  47. 68 roll_result = calculate_roll_result(sorted_dice_values)
  48. 68 test_value = roll_result + @modifier
  49. 68 diff = test_value - @difficulty
  50. # diff と @difficulty との比較の演算子が変わるので、send で対応
  51. # 例:COMPARE_OP が :>= ならば、diff >= 0 と同じ
  52. 68 success = !fumble && diff.send(self.class::COMPARE_OP, 0)
  53. 68 critical = diff >= 10
  54. output_parts = [
  55. 68 "(#{expression()})",
  56. test_value_expression(sorted_dice_values, roll_result),
  57. test_value,
  58. result_str(success, fumble, critical, diff)
  59. ]
  60. 68 return output_parts.join(' > ')
  61. end
  62. 1 private
  63. # 数式表現を返す
  64. # @return [String]
  65. 1 def expression
  66. 68 modifier_str = Format.modifier(@modifier)
  67. 68 return "#{@num}D10#{modifier_str}#{self.class::COMPARE_OP}#{@difficulty}"
  68. end
  69. # 判定値の数式表現を返す
  70. # @param [Array<Integer>] dice_values 出目の配列
  71. # @param [Integer] roll_result ダイスロール結果の値
  72. # @return [String]
  73. 1 def test_value_expression(dice_values, roll_result)
  74. 68 dice_str = dice_values.join(',')
  75. 68 modifier_str = Format.modifier(@modifier)
  76. 68 return "#{roll_result}[#{dice_str}]#{modifier_str}"
  77. end
  78. # 判定結果の文字列を返す
  79. # @param [Boolean] success 成功したか
  80. # @param [Boolean] fumble ファンブルだったか
  81. # @param [Boolean] critical クリティカルだったか
  82. # @param [Integer] _diff 判定値と難易度の差
  83. # @return [String]
  84. 1 def result_str(success, fumble, critical, _diff)
  85. 68 then: 3 else: 65 return 'ファンブル' if fumble
  86. 65 then: 19 else: 46 return 'クリティカル' if critical
  87. 46 then: 5 else: 41 return success ? '成功' : '失敗'
  88. end
  89. # ダイスロール結果を計算する
  90. #
  91. # 以下のうち最大のものを返す。
  92. #
  93. # * 出目の最大値
  94. # * ゾロ目の和の最大値
  95. # * ストレート(昇順で連続する3個以上の値)の和の最大値
  96. #
  97. # @param [Array<Integer>] sorted_dice_values 昇順でソートされた出目の配列
  98. # @return [Integer]
  99. 1 def calculate_roll_result(sorted_dice_values)
  100. 68 highest_single_roll = sorted_dice_values.last
  101. 68 sum_of_highest_set_of_multiples = sorted_dice_values
  102. .group_by(&:itself)
  103. .values
  104. .map(&:sum)
  105. .max
  106. candidates = [
  107. 68 highest_single_roll,
  108. sum_of_highest_set_of_multiples,
  109. sum_of_largest_straight(sorted_dice_values)
  110. ]
  111. 68 return candidates.max
  112. end
  113. # ストレートの和の最大値を求める
  114. #
  115. # ストレートとは、昇順で3個以上連続した値のこと。
  116. #
  117. # @param [Array<Integer>] sorted_dice_values 昇順にソートされた出目の配列
  118. # @return [Integer] ストレートの和の最大値
  119. # @return [0] ストレートが存在しなかった場合
  120. 1 def sum_of_largest_straight(sorted_dice_values)
  121. # 出目が3個未満ならば、ストレートは存在しない
  122. 68 then: 0 else: 68 return 0 if sorted_dice_values.length < 3
  123. # ストレートの和の最大値
  124. 68 max_sum = 0
  125. # 連続した値の数
  126. 68 n_consecutive_values = 0
  127. # 連続した値の和
  128. 68 sum = 0
  129. # 直前の値
  130. # 初期値を負の値にして、最初の値と連続にならないようにする
  131. 68 last = -1
  132. 68 sorted_dice_values.uniq.each do |value|
  133. # 値が連続でなければ、状態を初期化する(現在の値を連続1個目とする)
  134. 419 then: 201 else: 218 if value - last > 1
  135. 201 n_consecutive_values = 1
  136. 201 sum = value
  137. 201 last = value
  138. 201 next
  139. end
  140. # 連続した値なので溜める
  141. 218 n_consecutive_values += 1
  142. 218 sum += value
  143. 218 last = value
  144. # ストレートならば、和の最大値を更新する
  145. 218 then: 109 else: 109 if n_consecutive_values >= 3 && sum > max_sum
  146. 109 max_sum = sum
  147. end
  148. end
  149. 68 return max_sum
  150. end
  151. end
  152. # 対抗判定のノード
  153. 1 class Contest < Test
  154. # 判定で用いる比較演算子
  155. 1 COMPARE_OP = :>
  156. # 判定結果の文字列を返す
  157. #
  158. # 成功した場合(クリティカルを含む)、ダメージロールのコマンドを末尾に
  159. # 追加する。
  160. #
  161. # @param [Boolean] success 成功したか
  162. # @param [Integer] diff 判定値と難易度の差
  163. # @return [String]
  164. 1 def result_str(success, _fumble, _critical, diff)
  165. 30 formatted = super
  166. 30 then: 10 if success
  167. 10 damage_roll_num = (diff / 5.0).ceil
  168. 10 damage_roll = "#{damage_roll_num}D10"
  169. 10 "#{formatted}(ダメージ:#{damage_roll})"
  170. else: 20 else
  171. 20 formatted
  172. end
  173. end
  174. end
  175. # ダイスボットを初期化する
  176. 1 def initialize(command)
  177. 68 super(command)
  178. # 加算ロールで出目をソートする
  179. 68 @sort_add_dice = true
  180. end
  181. # ダイスボット固有コマンドの処理を行う
  182. # @param [String] command コマンド
  183. # @return [String] ダイスボット固有コマンドの結果
  184. # @return [nil] 無効なコマンドだった場合
  185. 1 def eval_game_system_specific_command(command)
  186. 68 node = parse(command)
  187. 68 else: 68 then: 0 return nil unless node
  188. 68 return node.execute(@randomizer)
  189. end
  190. 1 private
  191. # 判定コマンドの正規表現
  192. 1 TEST_RE = /\A(\d+)D10((?:[-+]\d+)+)?(>=?)(\d+)\z/.freeze
  193. # 構文解析する
  194. # @param [String] command コマンド
  195. # @return [Test, Contest] 判定のノード
  196. # @return [nil] 無効なコマンドだった場合
  197. 1 def parse(command)
  198. 68 m = TEST_RE.match(command)
  199. 68 else: 68 then: 0 return nil unless m
  200. 68 num = m[1].to_i
  201. 68 then: 4 else: 64 modifier = m[2] ? ArithmeticEvaluator.eval(m[2]) : 0
  202. 68 then: 30 else: 38 node_class = m[3] == '>' ? Contest : Test
  203. 68 difficulty = m[4].to_i
  204. 68 return node_class.new(num, modifier, difficulty)
  205. end
  206. end
  207. end
  208. end

lib/bcdice/game_system/Cthulhu_ChineseTraditional.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/Cthulhu"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Cthulhu_ChineseTraditional < Cthulhu
  6. # ゲームシステムの識別子
  7. 1 ID = 'Cthulhu:ChineseTraditional'
  8. # ゲームシステム名
  9. 1 NAME = '克蘇魯神話'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Chinese Traditional:克蘇魯神話'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. c=爆擊率 / f=大失敗值 / s=特殊
  15. 1d100<=n c・f・s全關閉(只進行單純數值比較判定)
  16. ・cfs付註判定指令
  17. CC 1d100擲骰 c=1、f=100
  18. CCB 同上、c=5、f=96
  19. 例:CC<=80 (以技能值80來判定。cf適用於1%規則)
  20. 例:CCB<=55 (以技能值55來判定。cf適用於5%規則)
  21. ・關於組合骰組
  22. CBR(x,y) c=1、f=100
  23. CBRB(x,y) c=5、f=96
  24. ・關於對抗骰
  25. RES(x-y) c=1、f=100
  26. RESB(x-y) c=5、f=96
  27. ※故障率判定
  28. ・CC(x) c=1、f=100
  29. x=故障率。擲出骰值x以上時、需在大失敗發生同時輸出(參照「大失敗&故障」)
  30. 沒有大失敗時,無論成功或失敗只需參考[故障]來輸出(並非成功或失敗來輸出,而是覆蓋上去並對其輸出)
  31. ・CCB(x) c=5、f=96
  32. 同上
  33. INFO_MESSAGE_TEXT
  34. 1 register_prefix_from_super_class()
  35. 1 def initialize(command)
  36. 100 super(command)
  37. 100 @locale = :zh_hant
  38. end
  39. end
  40. end
  41. end

lib/bcdice/game_system/Cthulhu_English.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/Cthulhu"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Cthulhu_English < Cthulhu
  6. # ゲームシステムの識別子
  7. 1 ID = 'Cthulhu:English'
  8. # ゲームシステム名
  9. 1 NAME = 'Call of Cthulhu'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:English:Call of Cthulhu'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. c=Critical Rate / f=Fumble Rate / s=Special
  15. 1d100<=n c・f・s AllOff(Does Simple Numeric Comparison Only)
  16. ・Roll Command that determines cfs
  17. CC Does a 1d100 roll c=1、f=100
  18. CCB Same as above、c=5、f=96
  19. Ex:CC<=80 (Rolls using 80 as skill value with 1% cf rule applied)
  20. Ex:CCB<=55 (Rolls using 55 as skill value with 5% cf rule applied)
  21. ・About Roll Combination
  22. CBR(x,y) c=1、f=100
  23. CBRB(x,y) c=5、f=96
  24. ・About Opposed Rolls
  25. RES(x-y) c=1、f=100
  26. RESB(x-y) c=5、f=96
  27. ※Malfunction Number Determination
  28. ・CC(x) c=1、f=100
  29. x=Malfunction Number. Outputs(text "Fumble&Malfunction")together, when roll result is equal or above x, and fumble happens simultaneously.
  30. If not a fumble, outputs text "Malfunction" regardless of success/failure(Outputs the overwritten result, not outputting success/failure)
  31. ・CCB(x) c=5、f=96
  32. Same as above
  33. INFO_MESSAGE_TEXT
  34. 1 register_prefix_from_super_class()
  35. 1 def initialize(command)
  36. 105 super(command)
  37. 105 @locale = :en_us
  38. end
  39. end
  40. end
  41. end

lib/bcdice/game_system/Cthulhu_Korean.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/Cthulhu"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Cthulhu_Korean < Cthulhu
  6. # ゲームシステムの識別子
  7. 1 ID = 'Cthulhu:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '크툴루'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:크툴루'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. c=크리티컬치 / f=펌블치 / s=스페셜
  15. 1d100<=n c・f・s 모두 오프(단순하게 수치만을 뽑아낼 때 사용)
  16. ・cfs이 붙는 판정의 커맨드
  17. CC 1d100 판정을 행함 c=1、f=100
  18. CCB 위와 동일、c=5、f=96
  19. 예:CC<=80 (기능치 80로 행휘판정. 1%룰으로 cf적용)
  20. 예:CCB<=55 (기능치 55로 행휘판정. 5%룰으로 cf적용)
  21. ・경우의 수 판정에 대해서
  22. CBR(x,y) c=1、f=100
  23. CBRB(x,y) c=5、f=96
  24. ・저항 판정에 대해서
  25. RES(x-y) c=1、f=100
  26. RESB(x-y) c=5、f=96
  27. ※고장 넘버 판정
  28. ・CC(x) c=1、f=100
  29. x=고장 넘버. 주사위 눈x이상이 나온 후에, 펌블이 동시에 발생했을 경우. 모두 출력한다. (텍스트 「펌블&고장」)
  30. 펌블이 아닌 경우, 성공・실패에 관련되지 않고 「고장」만을 출력한다. (성공・실패를 출력하지 않고 덧쓰기한 것을 출력하는 형태)
  31. ・CCB(x) c=5、f=96
  32. 위와 동일
  33. INFO_MESSAGE_TEXT
  34. 1 register_prefix_from_super_class()
  35. 1 def initialize(command)
  36. 100 super(command)
  37. 100 @locale = :ko_kr
  38. end
  39. end
  40. end
  41. end

lib/bcdice/game_system/Cthulhu_SimplifiedChinese.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/Cthulhu"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Cthulhu_SimplifiedChinese < Cthulhu
  6. # ゲームシステムの識別子
  7. 1 ID = 'Cthulhu:SimplifiedChinese'
  8. # ゲームシステム名
  9. 1 NAME = '克苏鲁的呼唤 第六版'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Simplified Chinese:克苏鲁的呼唤 第六版'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. c=大成功值 / f=大失败值 / s=极难成功
  15. 1d100<=n c・f・s全部关闭(只进行数值比较判定)
  16. ・带cfs判定的判定指令
  17. CC 掷1d100骰 c=1、f=100
  18. CCB 同上,c=5、f=96
  19. 例:CC<=80 (以80技能値进行行为判定。并以1%的标准使用cf的值)
  20. 例:CCB<=55 (以55技能値进行行为判定。并以5%的标准使用cf的值)
  21. ・关于组合骰
  22. CBR(x,y) c=1、f=100
  23. CBRB(x,y) c=5、f=96
  24. ・关于对抗骰
  25. RES(x-y) c=1、f=100
  26. RESB(x-y) c=5、f=96
  27. ※故障值判定
  28. ・CC(x) c=1、f=100
  29. x=故障值。骰点在x以上并且发生大失败时,会和大失败一起显示(文本为「大失败&故障」)
  30. 没有发生大失败时,与成功或失败无关,文斗都会显示为「故障」(不显示成功或失败的情况下进行覆盖显示)
  31. ・CCB(x) c=5、f=96
  32. 同上
  33. INFO_MESSAGE_TEXT
  34. 1 register_prefix_from_super_class()
  35. 1 def initialize(command)
  36. 103 super(command)
  37. 103 @locale = :zh_hans
  38. end
  39. end
  40. end
  41. end

lib/bcdice/game_system/CyberpunkRed.rb

100.0% lines covered

94.74% branches covered

58 relevant lines. 58 lines covered and 0 lines missed.
19 total branches, 18 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/cyberpunk_red/tables"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class CyberpunkRed < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'CyberpunkRed'
  8. # ゲームシステム名
  9. 1 NAME = 'サイバーパンクRED'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'さいはあはんくれつと'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~HELP
  14. ・判定 CPx+y>z
  15.  (x=能力値と技能値の合計、y=修正値、z=難易度 or 受動側 x、y、zは省略可)
  16.  例)CP12 CP10+2>12 CP7-1 CP8+4 CP7>12 CP CP>9
  17. 各種表
  18. ・致命的損傷表
  19.  FFD :身体への致命的損傷
  20.  HFD :頭部への致命的損傷
  21. ・遭遇表
  22.  NCDT :ナイトシティ(日中)
  23.  NCMT :ナイトシティ(深夜)
  24. ・スクリームシート
  25.  SCSR :スクリームシート(ランダム)
  26.  SCST :スクリームシート分類
  27.  SCSA :ヘッドラインA
  28.  SCSB :ヘッドラインB
  29.  SCSC :ヘッドラインC
  30. ・最寄りの自販機
  31.  VMCR :最寄りの自販機表
  32.  VMCT :自販機タイプ決定表
  33.  VMCE :食品
  34.  VMCF :ファッション
  35.  VMCS :変なもの
  36. ・ボデガの客
  37.  STORE :ボデガの客と店員
  38.  STOREA :店主またはレジ係
  39.  STOREB :変わった客その1
  40.  STOREC :変わった客その2
  41. ・夜の市
  42.  NMCT :商品の分野
  43.  NMCFO :食品とドラッグ
  44.  NMCME :個人用電子機器
  45.  NMCWE :武器と防具
  46.  NMCCY :サイバーウェア
  47.  NMCFA :衣料品とファッションウェア
  48.  NMCSU :サバイバル用品
  49. HELP
  50. 1 TABLES = translate_tables(@locale)
  51. # 判定の正規表現
  52. 1 CP_RE = /^CP(?<ability>\d+)?(?<modifier>[+-]\d+)?(?<target>>=\d+)?/.freeze
  53. 1 def initialize(command)
  54. 112 super(command)
  55. 112 @sort_add_dice = false
  56. 112 @d66_sort_type = D66SortType::NO_SORT
  57. end
  58. 1 def eval_game_system_specific_command(command)
  59. 112 debug("eval_game_system_specific_command begin string", command)
  60. 112 cp_roll_result(command) || roll_tables(command, self.class::TABLES)
  61. end
  62. 1 private_constant :CP_RE
  63. 1 def cp_roll_result(command)
  64. 112 parser = Command::Parser.new('CP', round_type: RoundType::FLOOR)
  65. .enable_suffix_number
  66. .restrict_cmp_op_to(nil, :>)
  67. 112 parsed = parser.parse(command)
  68. 112 then: 82 else: 30 return nil if parsed.nil?
  69. 30 dice_cnt = 1
  70. 30 dice_face = 10
  71. 30 modify_number = 0
  72. 30 total = 0
  73. 30 result = Result.new
  74. 30 dices = [@randomizer.roll_once(dice_face)]
  75. 30 total += dices.first
  76. 30 then: 12 else: 18 modify_number += parsed.suffix_number if parsed.suffix_number
  77. 30 then: 30 else: 0 modify_number += parsed.modify_number if parsed.modify_number
  78. 30 total += modify_number
  79. 30 else: 14 case dices.first
  80. when: 8 when 10 # critical
  81. 8 dices << @randomizer.roll_once(dice_face)
  82. 8 total += dices.last
  83. 8 result.critical = true
  84. when: 8 when 1 # fumble
  85. 8 dices << @randomizer.roll_once(dice_face)
  86. 8 total -= dices.last
  87. 8 result.fumble = true
  88. end
  89. 30 then: 16 else: 14 if parsed.target_number
  90. 16 result.condition = total > parsed.target_number
  91. end
  92. 30 result.text = "(#{dice_cnt}D#{dice_face}#{Format.modifier(modify_number)}#{parsed.cmp_op}#{parsed.target_number})"
  93. 30 result.text += ' > '
  94. 30 result.text += "#{dices.first}[#{dices.first}]#{Format.modifier(modify_number)}"
  95. 30 result.text += ' > '
  96. 30 then: 8 else: 22 if result.critical?
  97. 8 result.text += "#{translate('CyberpunkRed.critical')} > "
  98. 8 result.text += "#{dices.last}[#{dices.last}] > "
  99. end
  100. 30 then: 8 else: 22 if result.fumble?
  101. 8 result.text += "#{translate('CyberpunkRed.fumble')} > "
  102. 8 result.text += "#{dices.last}[#{dices.last}] > "
  103. end
  104. 30 result.text += total.to_s
  105. 30 then: 8 else: 22 if result.success?
  106. 8 result.text += " > #{translate('success')}"
  107. end
  108. 30 then: 8 else: 22 if result.failure?
  109. 8 result.text += " > #{translate('failure')}"
  110. end
  111. 30 return result
  112. end
  113. 1 register_prefix('CP', TABLES.keys)
  114. end
  115. end
  116. end

lib/bcdice/game_system/CyberpunkRed_Korean.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/CyberpunkRed"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class CyberpunkRed_Korean < CyberpunkRed
  6. # ゲームシステムの識別子
  7. 1 ID = 'CyberpunkRed:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '사이버펑크 RED'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:사이버펑크'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~HELP
  14. ・판정 CPx+y>z
  15.  (x=능력치와 기능치의 합(base)、y=수정치(mod)、z=난이도(DV) or 방어자의 값 x、y、z는 생략 가능)
  16.  예시)CP12, CP10+2>12, CP7-1, CP8+4, CP7>12, CP, CP>9
  17. 각종 표
  18. ・치명적인 손상표
  19.  FFD :신체에 치명적 손상
  20.  HFD :머리에 치명적 손상
  21. ・조우 표
  22.  NCDT :나이트시티(낮)
  23.  NCMT :나이트 시티(심야)
  24. ・스크림 시트(신문)
  25.  SCSR :스크림 시트(랜덤)
  26.  SCST :스크림 시트 카테고리
  27.  SCSA :헤드 라인A
  28.  SCSB :헤드 라인B
  29.  SCSC :헤드 라인C
  30. ・가장 가까운 자판기
  31.  VMCR :가장 가까운 자판기표
  32.  VMCT :자판기 유형 결정표
  33.  VMCE :식품
  34.  VMCF :패션
  35.  VMCS :이상한 물건
  36. ・보데가(상점) 손님
  37.  STORE :상점 손님과 점원
  38.  STOREA :점주 또는 계산원
  39.  STOREB :별난 손님 1
  40.  STOREC :별난 손님 2
  41. ・야시장
  42.  NMCT :상품의 분야
  43.  NMCFO :음식과 약물
  44.  NMCME :개인용 전자기기
  45.  NMCWE :무기와 갑옷
  46.  NMCCY :사이버웨어
  47.  NMCFA :의류 및 패션웨어
  48.  NMCSU :생존 장비(servival gear)
  49. HELP
  50. 1 def initialize(command)
  51. 56 super(command)
  52. 56 @locale = :ko_kr
  53. end
  54. 1 register_prefix_from_super_class()
  55. 1 TABLES = translate_tables(:ko_kr)
  56. end
  57. end
  58. end

lib/bcdice/game_system/DarkBlaze.rb

91.74% lines covered

75.93% branches covered

109 relevant lines. 100 lines covered and 9 lines missed.
54 total branches, 41 branches covered and 13 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/normalize'
  3. 1 require 'bcdice/format'
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class DarkBlaze < Base
  7. # ゲームシステムの識別子
  8. 1 ID = 'DarkBlaze'
  9. # ゲームシステム名
  10. 1 NAME = 'ダークブレイズ'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = 'たあくふれいす'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  15. ・行為判定 (DBxy#n)
  16.  行為判定専用のコマンドです。
  17.  "DB(能力)(技能)#(修正)"でロールします。Rコマンド(3R6+n[x,y]>=m mは難易度)に読替をします。
  18.  クリティカルとファンブルも自動で処理されます。
  19.  DB@x@y#m と DBx,y#m にも対応しました。
  20.  例)DB33   DB32#-1   DB@3@1#1   DB3,2   DB23#1>=4   3R6+1[3,3]>=4
  21. ・掘り出し袋表 (BTx)
  22.  "BT(ダイス数)"で掘り出し袋表を自動で振り、結果を表示します。
  23.  例)BT1   BT2   BT[1...3]
  24. INFO_MESSAGE_TEXT
  25. 1 register_prefix('DB', 'BT', '3R6')
  26. 1 def replace_text(string)
  27. 70 else: 60 then: 10 return string unless string =~ /DB/i
  28. 70 string = string.gsub(/DB(\d),(\d)/) { "DB#{Regexp.last_match(1)}#{Regexp.last_match(2)}" }
  29. 70 string = string.gsub(/DB@(\d)@(\d)/) { "DB#{Regexp.last_match(1)}#{Regexp.last_match(2)}" }
  30. 90 string = string.gsub(/DB(\d)(\d)(#(\d[+\-\d]*))/) { "3R6+#{Regexp.last_match(4)}[#{Regexp.last_match(1)},#{Regexp.last_match(2)}]" }
  31. 70 string = string.gsub(/DB(\d)(\d)(#([+\-\d]*))/) { "3R6#{Regexp.last_match(4)}[#{Regexp.last_match(1)},#{Regexp.last_match(2)}]" }
  32. 80 string = string.gsub(/DB(\d)(\d)/) { "3R6[#{Regexp.last_match(1)},#{Regexp.last_match(2)}]" }
  33. 60 return string
  34. end
  35. 1 def check_roll(string)
  36. 70 string = replace_text(string)
  37. 70 else: 70 then: 0 return nil unless (m = /(^|\s)S?(3[rR]6([+\-\d]+)?(\[(\d+),(\d+)\])(([>=]+)(\d+))?)(\s|$)/i.match(string))
  38. 70 string = m[2]
  39. 70 mod = 0
  40. 70 abl = 1
  41. 70 skl = 1
  42. 70 signOfInequality = ""
  43. 70 diff = 0
  44. 70 then: 50 else: 20 mod = ArithmeticEvaluator.eval(m[3]) if m[3]
  45. 70 then: 70 else: 0 if m[4]
  46. 70 abl = m[5].to_i
  47. 70 skl = m[6].to_i
  48. end
  49. 70 then: 20 else: 50 if m[7]
  50. 20 cmp_op = Normalize.comparison_operator(m[8])
  51. 20 signOfInequality = Format.comparison_operator(cmp_op)
  52. 20 diff = m[9].to_i
  53. end
  54. 70 total, out_str = get_dice(mod, abl, skl)
  55. 70 output = "(#{string}) > #{out_str}"
  56. 70 then: 20 else: 50 if signOfInequality != "" # 成功度判定処理
  57. 20 cmp_op = Normalize.comparison_operator(signOfInequality)
  58. 20 output +=
  59. 20 then: 13 if total.send(cmp_op, diff)
  60. 13 " > 成功"
  61. else: 7 else
  62. 7 " > 失敗"
  63. end
  64. end
  65. 70 return output
  66. end
  67. 1 def get_dice(mod, abl, skl)
  68. 70 total = 0
  69. 70 crit = 0
  70. 70 fumble = 0
  71. 70 dice_c = 3 + mod.abs
  72. 70 dice_arr = @randomizer.roll_barabara(dice_c, 6).sort
  73. 70 dice_str = dice_arr.join(",")
  74. 70 3.times do |i|
  75. 210 ch = dice_arr[i]
  76. 210 then: 30 else: 180 if mod < 0
  77. 30 ch = dice_arr[dice_c - i - 1]
  78. end
  79. 210 then: 123 else: 87 total += 1 if ch <= abl
  80. 210 then: 97 else: 113 total += 1 if ch <= skl
  81. 210 then: 76 else: 134 crit += 1 if ch <= 2
  82. 210 then: 55 else: 155 fumble += 1 if ch >= 5
  83. end
  84. 70 resultText = ""
  85. 70 then: 5 else: 65 if crit >= 3
  86. 5 resultText = " > クリティカル"
  87. 5 total = 6 + skl
  88. end
  89. 70 then: 1 else: 69 if fumble >= 3
  90. 1 resultText = " > ファンブル"
  91. 1 total = 0
  92. end
  93. 70 output = "#{total}[#{dice_str}]#{resultText}"
  94. 70 return total, output
  95. end
  96. 1 def eval_game_system_specific_command(command)
  97. 100 then: 30 else: 70 if (m = /^BT(\d)?$/i.match(command))
  98. 30 then: 30 else: 0 dice = m[1]&.to_i || 1
  99. 30 return get_horidasibukuro_table(dice)
  100. end
  101. 70 return check_roll(command)
  102. end
  103. # ** 掘り出し袋表
  104. 1 def get_horidasibukuro_table(dice)
  105. 30 output = '1'
  106. 30 material_kind = [ # 2D6
  107. "蟲甲", # 5
  108. "金属", # 6
  109. "金貨", # 7
  110. "植物", # 8
  111. "獣皮", # 9
  112. "竜鱗", # 10
  113. "レアモノ", # 11
  114. "レアモノ", # 12
  115. ]
  116. 30 magic_stone = [ # 1D3
  117. "火炎石",
  118. "雷撃石",
  119. "氷結石",
  120. ]
  121. 30 num1 = @randomizer.roll_sum(2, 6)
  122. 30 num2 = @randomizer.roll_sum(dice, 6)
  123. 30 debug('dice', dice)
  124. 30 debug('num1', num1)
  125. 30 debug('num2', num2)
  126. 30 then: 5 if num1 <= 4
  127. 5 num2 = @randomizer.roll_once(6)
  128. 5 magic_stone_result = (magic_stone[(num2 / 2).to_i - 1])
  129. 5 else: 25 output = "《#{magic_stone_result}》を#{dice}個獲得"
  130. 25 then: 6 elsif num1 == 7
  131. 6 output = "《金貨》を#{num2}枚獲得"
  132. else: 19 else
  133. 19 type = material_kind[num1 - 5]
  134. 19 then: 6 if num2 <= 3
  135. 6 else: 13 output = "《#{type} I》を1個獲得"
  136. 13 then: 4 elsif num2 <= 5
  137. 4 else: 9 output = "《#{type} I》を2個獲得"
  138. 9 then: 7 elsif num2 <= 7
  139. 7 else: 2 output = "《#{type} I》を3個獲得"
  140. 2 then: 2 elsif num2 <= 9
  141. 2 else: 0 output = "《#{type} II》を1個獲得"
  142. then: 0 elsif num2 <= 11
  143. else: 0 output = "《#{type} I》を2個《#{type} II》を1個獲得"
  144. then: 0 elsif num2 <= 13
  145. else: 0 output = "《#{type} I》を2個《#{type} II》を2個獲得"
  146. then: 0 elsif num2 <= 15
  147. else: 0 output = "《#{type} III》を1個獲得"
  148. then: 0 elsif num2 <= 17
  149. output = "《#{type} II》を2個《#{type} III》を1個獲得"
  150. else: 0 else
  151. output = "《#{type} II》を2個《#{type} III》を2個獲得"
  152. end
  153. end
  154. 30 then: 30 else: 0 if output != '1'
  155. 30 output = "掘り出し袋表[#{num1},#{num2}] > #{output}"
  156. end
  157. 30 return output
  158. end
  159. end
  160. end
  161. end

lib/bcdice/game_system/DarkDaysDrive.rb

100.0% lines covered

92.86% branches covered

34 relevant lines. 34 lines covered and 0 lines missed.
14 total branches, 13 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class DarkDaysDrive < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'DarkDaysDrive'
  7. # ゲームシステム名
  8. 1 NAME = 'ダークデイズドライブ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'たあくていすとらいふ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定
  14. スペシャル/ファンブル/成功/失敗を判定
  15. ・各種表
  16. RTTn ランダム特技決定表(n:分野番号、省略可能)
  17. RCT ランダム分野決定表
  18. ABRT アビリティ決定表
  19. DT ダメージ表
  20. FT 失敗表
  21. GJT 大成功表
  22. ITT 移動トラブル表
  23. NTT 任務トラブル表
  24. STT 襲撃トラブル表
  25. HTT 変身トラブル表
  26. DET ドライブイベント表
  27. BET ブレイクイベント表
  28. CT キャンプ表
  29. KZT 関係属性表
  30. IA イケメンアクション決定表
  31. IAA 遠距離 IAB 移動 IAC 近距離 IAD 善人 IAE 悪人
  32. IAF 幼い IAG バカ IAH 渋い IAI 賢い IAJ 超自然
  33. IAX イケメンアクション決定表 → IA表
  34. ■本格的な戦闘
  35. CAC センターの行動決定
  36. DDC 対話ダメージ表
  37. ・D66ダイス昇順
  38. INFO_MESSAGE_TEXT
  39. 1 def initialize(command)
  40. 56 super(command)
  41. 56 @d66_sort_type = D66SortType::ASC
  42. end
  43. # ゲーム別成功度判定(2D6)
  44. 1 def result_2d6(total, dice_total, _dice_list, cmp_op, target)
  45. 7 else: 7 then: 0 return nil unless cmp_op == :>=
  46. 7 then: 2 if dice_total <= 2
  47. 2 else: 5 Result.fumble("ファンブル(判定失敗。失敗表(FT)を追加で1回振る)")
  48. 5 then: 2 elsif dice_total >= 12
  49. 2 else: 3 Result.critical("スペシャル(判定成功。大成功表(GJT)を1回使用可能)")
  50. 3 then: 1 elsif target == "?"
  51. 1 else: 2 Result.nothing
  52. 2 then: 1 elsif total >= target
  53. 1 Result.success("成功")
  54. else: 1 else
  55. 1 Result.failure("失敗")
  56. end
  57. end
  58. 1 def eval_game_system_specific_command(command)
  59. 49 roll_tables(command, TABLES) ||
  60. command_iax(command) ||
  61. RTT.roll_command(randomizer, command)
  62. end
  63. 1 private
  64. 1 def command_iax(command)
  65. 6 else: 2 then: 4 return nil unless command == "IAX"
  66. 2 ia = TABLES["IA"].choice(@randomizer.roll_d66(D66SortType::ASC))
  67. 2 m = ia.body.match(/\(([A-Z]+)\)/)
  68. 2 else: 1 then: 1 return ia unless m
  69. 1 ia2 = TABLES[m[1]].choice(@randomizer.roll_once(6))
  70. 1 return "#{ia} > #{ia2}"
  71. end
  72. 1 RTT = DiceTable::SaiFicSkillTable.new(
  73. [
  74. ['背景', ['呪い', '絶望', '孤児', '死別', '一般人', '獲物', '憧れ', '友人', '挑戦者', '血縁', '永遠']],
  75. ['仕事', ['脅迫', '捨てる', '拉致', '盗む', 'ハッキング', '侵入', '変装', 'だます', '隠す', 'のぞく', '聞き出す']],
  76. ['捜索', ['トイレ', '食事', '自然', '運動施設', '街', '友愛会', '暗部', '史跡', '文化施設', '温泉', '宿泊']],
  77. ['趣味', ['お酒', 'グルメ', 'ダンス', 'スポーツ', '健康', 'ファッション', '恋愛', 'フェス', '音楽', '物語', '学問']],
  78. ['雰囲気', ['だらしない', 'のんびり', '暖かい', '明るい', '甘い', '普通', '洗練', '渋い', '静か', '真面目', '冷たい']],
  79. ['戦闘法', ['忍術', '古武術', '剣術', '棒術', '拳法', 'ケンカ', '総合格闘技', 'レスリング', '軍隊格闘術', '射撃', '弓術']],
  80. ],
  81. rtt_format: "ランダム指定特技表(%<category_dice>d,%<row_dice>d) > %<category_name>s《%<skill_name>s》"
  82. )
  83. TABLES = {
  84. 1 "ABRT" => DiceTable::D66Table.new(
  85. "アビリティ決定表",
  86. D66SortType::ASC,
  87. {
  88. 11 => "インストラクター(P155)",
  89. 12 => "運送業(P155)",
  90. 13 => "運転手(P155)",
  91. 14 => "カフェ店員(P155)",
  92. 15 => "趣味人(P155)",
  93. 16 => "ショップ店員(P155)",
  94. 22 => "正社員(P156)",
  95. 23 => "大工(P156)",
  96. 24 => "探偵(P156)",
  97. 25 => "バイヤー(P156)",
  98. 26 => "俳優(P156)",
  99. 33 => "派遣社員(P156)",
  100. 34 => "犯罪者(P157)",
  101. 35 => "バンドマン(P157)",
  102. 36 => "バーテンダー(P157)",
  103. 44 => "ヒモ(P157)",
  104. 45 => "ホスト(P157)",
  105. 46 => "ホテルマン(P157)",
  106. 55 => "無職(P158)",
  107. 56 => "用心棒(P158)",
  108. 66 => "料理人(P158)"
  109. }
  110. ),
  111. "DT" => DiceTable::Table.new(
  112. "ダメージ表",
  113. "1D6",
  114. [
  115. "疲れ",
  116. "痛み",
  117. "焦り",
  118. "不調",
  119. "ショック",
  120. "ケガ"
  121. ]
  122. ),
  123. "FT" => DiceTable::Table.new(
  124. "失敗表",
  125. "1D6",
  126. [
  127. "任意のアイテムを一つ失う",
  128. "1ダメージを受ける",
  129. "【所持金ランク】が1減少する(最低0)",
  130. "2ダメージを受ける",
  131. "【所持金ランク】が2減少する(最低0)",
  132. "標的レベルが1増加する"
  133. ]
  134. ),
  135. "GJT" => DiceTable::Table.new(
  136. "大成功表",
  137. "1D6",
  138. [
  139. "主人からお褒めの言葉をいただく",
  140. "ダメージを1回復する",
  141. "ダメージを1回復する",
  142. "関係のチェックを一つ消す",
  143. "ダメージを2回復する",
  144. "【所持金ランク】が1増加する"
  145. ]
  146. ),
  147. "ITT" => DiceTable::Table.new(
  148. "移動トラブル表",
  149. "1D6",
  150. [
  151. "検問(P220)",
  152. "急な腹痛(P220)",
  153. "黒煙(P221)",
  154. "蚊(P221)",
  155. "落とし物(P222)",
  156. "空腹(P222)"
  157. ]
  158. ),
  159. "NTT" => DiceTable::Table.new(
  160. "任務トラブル表",
  161. "1D6",
  162. [
  163. "通報(P223)",
  164. "プレッシャー(P223)",
  165. "マナー違反(P224)",
  166. "志願者(P224)",
  167. "仲間割れ(P225)",
  168. "狩人の噂(P225)"
  169. ]
  170. ),
  171. "STT" => DiceTable::Table.new(
  172. "襲撃トラブル表",
  173. "1D6",
  174. [
  175. "孤独な追跡者(P226)",
  176. "地元の若者たち(P226)",
  177. "V-FILES(P227)",
  178. "チンピラの群れ(P227)",
  179. "孤独な狩人(P228)",
  180. "狩人の群れ(P228)"
  181. ]
  182. ),
  183. "HTT" => DiceTable::D66Table.new(
  184. "変身トラブル表",
  185. D66SortType::NO_SORT,
  186. {
  187. 11 => "あれを食べたい(P214)",
  188. 12 => "あれを着たい(P214)",
  189. 13 => "あれを見たい(P215)",
  190. 14 => "あれを狩りたい(P215)",
  191. 15 => "あれを踊りたい(P216)",
  192. 16 => "あれに入りたい(P216)",
  193. 21 => "強奪(P217)",
  194. 22 => "暴行(P217)",
  195. 23 => "虐殺(P218)",
  196. 24 => "誘拐(P218)",
  197. 25 => "無精(P219)",
  198. 26 => "失踪(P219)",
  199. 31 => "あれを食べたい(P214)",
  200. 32 => "あれを着たい(P214)",
  201. 33 => "あれを見たい(P215)",
  202. 34 => "あれを狩りたい(P215)",
  203. 35 => "あれを踊りたい(P216)",
  204. 36 => "あれに入りたい(P216)",
  205. 41 => "強奪(P217)",
  206. 42 => "暴行(P217)",
  207. 43 => "虐殺(P218)",
  208. 44 => "誘拐(P218)",
  209. 45 => "無精(P219)",
  210. 46 => "失踪(P219)",
  211. 51 => "あれを食べたい(P214)",
  212. 52 => "あれを着たい(P214)",
  213. 53 => "あれを見たい(P215)",
  214. 54 => "あれを狩りたい(P215)",
  215. 55 => "あれを踊りたい(P216)",
  216. 56 => "あれに入りたい(P216)",
  217. 61 => "強奪(P217)",
  218. 62 => "暴行(P217)",
  219. 63 => "虐殺(P218)",
  220. 64 => "誘拐(P218)",
  221. 65 => "無精(P219)",
  222. 66 => "失踪(P219)"
  223. }
  224. ),
  225. "DET" => DiceTable::Table.new(
  226. "ドライブイベント表",
  227. "1D6",
  228. [
  229. "身の上話をする。目標が背景分野で選択している特技がドライブ判定の指定特技になる。",
  230. "スキル自慢をする。目標が仕事分野で選択している特技がドライブ判定の指定特技になる。",
  231. "むかし行った場所の話をする。目標が捜索分野で選択している特技がドライブ判定の指定特技になる。",
  232. "趣味の話をする。目標が趣味分野で選択している特技がドライブ判定の指定特技になる。",
  233. "テーマがない雑談をする。目標が雰囲気分野で選択している特技がドライブ判定の指定特技になる。",
  234. "物騒な話をする。目標が戦闘法分野で選択している特技がドライブ判定の指定特技になる。"
  235. ]
  236. ),
  237. "BET" => DiceTable::Table.new(
  238. "ブレイクイベント表",
  239. "1D6",
  240. [
  241. "イケメンの車は風光明美な場所に到着する。197ページの「観光地」を参照。",
  242. "イケメンの車は明るい光に照らされた小さな店に到着する。197ページの「コンビニ」を参照。",
  243. "イケメンの車は巨大かつ何でも売っている店に到着する。198ページの「ホームセンター」を参照。",
  244. "イケメンの車はドライバーたちの憩いの地に到着する。198ページの「サービスエリア」を参照。",
  245. "イケメンの車は大きなサービスエリアのような場所に到着する。199ページの「道の駅」を参照。",
  246. "イケメンの車は闇の底に隠された秘密の場所に到着する。199ページの「友愛会支部」を参照。"
  247. ]
  248. ),
  249. "CT" => DiceTable::Table.new(
  250. "キャンプ表",
  251. "1D6",
  252. [
  253. "無料仮眠所・いい感じの空き地:定員無制限/居住性-2/価格0/発見率2",
  254. "カプセルホテル:定員1/居住性-1/価格3/発見率2",
  255. "ラブホテル:定員2/居住性0/価格4/発見率1",
  256. "ビジネスホテル:定員2/居住性0/価格4/発見率1",
  257. "観光ホテル:定員4/居住性1/価格5/発見率1",
  258. "高級ホテル:定員4/居住性2/価格6/発見率0"
  259. ]
  260. ),
  261. "KZT" => DiceTable::Table.new(
  262. "関係属性表",
  263. "1D6",
  264. [
  265. "軽蔑",
  266. "反感",
  267. "混乱",
  268. "興味",
  269. "共感",
  270. "憧れ"
  271. ]
  272. ),
  273. "IA" => DiceTable::D66Table.new(
  274. "イケメンアクション決定表",
  275. D66SortType::ASC,
  276. {
  277. 11 => "遠距離(IAA)",
  278. 12 => "遠距離(IAA)",
  279. 13 => "移動(IAB)",
  280. 14 => "移動(IAB)",
  281. 15 => "近距離(IAC)",
  282. 16 => "近距離(IAC)",
  283. 22 => "善人(IAD)",
  284. 23 => "善人(IAD)",
  285. 24 => "悪人(IAE)",
  286. 25 => "悪人(IAE)",
  287. 26 => "幼い(IAF)",
  288. 33 => "幼い(IAF)",
  289. 34 => "バカ(IAG)",
  290. 35 => "バカ(IAG)",
  291. 36 => "渋い(IAH)",
  292. 44 => "渋い(IAH)",
  293. 45 => "賢い(IAI)",
  294. 46 => "賢い(IAI)",
  295. 55 => "超自然(IAJ)",
  296. 56 => "超自然(IAJ)",
  297. 66 => "振り直しor自由選択"
  298. }
  299. ),
  300. "IAA" => DiceTable::Table.new(
  301. "イケメンアクション(遠距離)表(P172)",
  302. "1D6",
  303. [
  304. "目を合わせて微笑む(かっこよさ:4)",
  305. "場所を譲る(かっこよさ:4)",
  306. "髪をかきあげる(かっこよさ:5)",
  307. "複雑なポーズで座る(かっこよさ:5)",
  308. "物憂げな表情で振り返る(かっこよさ:6)",
  309. "ものを上に持つ(かっこよさ:6)"
  310. ]
  311. ),
  312. "IAB" => DiceTable::Table.new(
  313. "イケメンアクション(移動)表(P172)",
  314. "1D6",
  315. [
  316. "車道側を歩く(かっこよさ:4)",
  317. "乗り物から降りる(かっこよさ:4)",
  318. "真剣な表情で近づく(かっこよさ:4)",
  319. "馬に乗る(かっこよさ:6)",
  320. "ダメージを受けつつ移動(かっこよさ:6)",
  321. "瞬間移動(かっこよさ:6)"
  322. ]
  323. ),
  324. "IAC" => DiceTable::Table.new(
  325. "イケメンアクション(近距離)表(P173)",
  326. "1D6",
  327. [
  328. "黙って見つめる(かっこよさ:3)",
  329. "ちょっとしたプレゼント(かっこよさ:3)",
  330. "顎クイ(かっこよさ:5)",
  331. "壁ドン(かっこよさ:5)",
  332. "お姫様抱っこ(かっこよさ:7)",
  333. "床ドン(かっこよさ:7)"
  334. ]
  335. ),
  336. "IAD" => DiceTable::Table.new(
  337. "イケメンアクション(善人)表(P173)",
  338. "1D6",
  339. [
  340. "手を引いて逃げる(かっこよさ:4)",
  341. "毛布を掛ける(かっこよさ:4)",
  342. "守る(かっこよさ:5)",
  343. "笑って去る(かっこよさ:5)",
  344. "全てを捧げる(かっこよさ:6)",
  345. "悪堕ち(かっこよさ:6)"
  346. ]
  347. ),
  348. "IAE" => DiceTable::Table.new(
  349. "イケメンアクション(悪人)表(P174)",
  350. "1D6",
  351. [
  352. "攻撃する(かっこよさ:4)",
  353. "暗く笑う(かっこよさ:4)",
  354. "奪う(かっこよさ:4)",
  355. "目論見を口にする(かっこよさ:6)",
  356. "罠にかける(かっこよさ:6)",
  357. "改心する(かっこよさ:6)"
  358. ]
  359. ),
  360. "IAF" => DiceTable::Table.new(
  361. "イケメンアクション(幼い)表(P174)",
  362. "1D6",
  363. [
  364. "甘える(かっこよさ:3)",
  365. "疲れる(かっこよさ:3)",
  366. "無邪気な発言(かっこよさ:5)",
  367. "おねだり(かっこよさ:5)",
  368. "上目遣い(かっこよさ:7)",
  369. "抱きつく(かっこよさ:7)"
  370. ]
  371. ),
  372. "IAG" => DiceTable::Table.new(
  373. "イケメンアクション(バカ)表(P175)",
  374. "1D6",
  375. [
  376. "苦悩する(かっこよさ:4)",
  377. "屈託のない笑顔(かっこよさ:4)",
  378. "転ぶ(かっこよさ:4)",
  379. "叫ぶ(かっこよさ:6)",
  380. "間違える(かっこよさ:6)",
  381. "怖がる(かっこよさ:6)"
  382. ]
  383. ),
  384. "IAH" => DiceTable::Table.new(
  385. "イケメンアクション(渋い)表(P175)",
  386. "1D6",
  387. [
  388. "説教(かっこよさ:4)",
  389. "気づかせる(かっこよさ:4)",
  390. "見守る(かっこよさ:5)",
  391. "残心(かっこよさ:5)",
  392. "称える(かっこよさ:6)",
  393. "いい位置を取る(かっこよさ:6)"
  394. ]
  395. ),
  396. "IAI" => DiceTable::Table.new(
  397. "イケメンアクション(賢い)表(P176)",
  398. "1D6",
  399. [
  400. "難しい本を読む(かっこよさ:3)",
  401. "アドバイスをする(かっこよさ:3)",
  402. "眼鏡を持ち上げる(かっこよさ:5)",
  403. "状況を解説する(かっこよさ:5)",
  404. "計算できなくなる(かっこよさ:7)",
  405. "大丈夫だと言う(かっこよさ:7)"
  406. ]
  407. ),
  408. "IAJ" => DiceTable::Table.new(
  409. "イケメンアクション(超自然)表(P176)",
  410. "1D6",
  411. [
  412. "水に濡れる(かっこよさ:4)",
  413. "風を纏う(かっこよさ:4)",
  414. "地割れ(かっこよさ:5)",
  415. "火を放つ(かっこよさ:5)",
  416. "闇を生み出す(かっこよさ:6)",
  417. "光る(かっこよさ:6)"
  418. ]
  419. ),
  420. "CAC" => DiceTable::Table.new(
  421. "センターの行動決定表",
  422. "1d6",
  423. [
  424. "逃走",
  425. "不意打ち",
  426. "連続行動",
  427. "対話",
  428. "威嚇",
  429. "攻撃"
  430. ]
  431. ),
  432. "DDC" => DiceTable::Table.new(
  433. "対話ダメージ表",
  434. "1d6",
  435. [
  436. "焦り",
  437. "焦り",
  438. "不調",
  439. "不調",
  440. "ショック",
  441. "ショック",
  442. ]
  443. )
  444. }.freeze
  445. 1 register_prefix(RTT.prefixes, TABLES.keys)
  446. end
  447. end
  448. end

lib/bcdice/game_system/DarkSouls.rb

100.0% lines covered

93.75% branches covered

45 relevant lines. 45 lines covered and 0 lines missed.
16 total branches, 15 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class DarkSouls < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'DarkSouls'
  7. # ゲームシステム名
  8. 1 NAME = 'ダークソウルTRPG'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'たあくそうるTRPG'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・行為判定:[n]DS[a±b][@t]  []内のコマンドは省略可
  14. ・能動判定:[n]ADS[a±b][@t]  FP消費を判定
  15.  n:ダイス数。省略時は「2」
  16.  a±b:修正値。「1+2-1」のように、複数定可
  17.  @t:目標値。省略時は達成値を、指定時は判定の正否を表示
  18. 例)DS → 2D6の達成値を表示
  19.   1DS → 1D6の達成値を表示
  20.   ADS+2-2 → 2D6+2の達成値を表示(能動判定)
  21.   DS+2@10 → 2D6+2で目標値10の判定
  22. MESSAGETEXT
  23. 1 register_prefix('(\d+)?(A)?DS([-+\d]*)(@\d+)?')
  24. 1 def eval_game_system_specific_command(command)
  25. 20 else: 20 then: 0 return nil unless (m = /(\d+)?(A)?DS([-+\d]*)(@(\d+))?$/i.match(command.upcase))
  26. 20 diceCount = (m[1] || 2).to_i
  27. 20 isActive = !m[2].nil?
  28. 20 modify = getValue(m[3])
  29. 20 target = (m[5] || 0).to_i
  30. 20 output = checkRoll(diceCount, isActive, modify, target)
  31. 20 return output
  32. end
  33. 1 def checkRoll(diceCount, isActive, modify, target)
  34. 20 dice_list = @randomizer.roll_barabara(diceCount, 6)
  35. 20 dice = dice_list.sum()
  36. 20 diceText = dice_list.join(",")
  37. 20 successValue = dice + modify
  38. 20 modifyText = getValueText(modify)
  39. 20 then: 13 else: 7 targetText = (target == 0 ? '' : ">=#{target}")
  40. 20 then: 9 else: 11 if isActive
  41. 9 diceArray = diceText.split(/,/).map(&:to_i)
  42. 26 focusDamage = diceArray.count { |i| i == 1 }
  43. 9 then: 5 else: 4 if focusDamage > 0
  44. 5 focusText = "■" * focusDamage
  45. 5 focusText = "(FP#{focusText}消費)"
  46. end
  47. end
  48. 20 result = "(#{diceCount}D6#{modifyText}#{targetText})"
  49. 20 result += " > #{dice}(#{diceText})#{modifyText}"
  50. 20 result += " > #{successValue}#{targetText}"
  51. 20 then: 7 else: 13 if target > 0
  52. 7 then: 5 if successValue >= target
  53. 5 result += " > 【成功】"
  54. else: 2 else
  55. 2 result += " > 【失敗】"
  56. end
  57. end
  58. 20 result += focusText.to_s
  59. 20 return result
  60. end
  61. 1 def getValue(text)
  62. 20 text ||= ""
  63. 20 return ArithmeticEvaluator.eval(text)
  64. end
  65. 1 def getValueText(value)
  66. 20 then: 15 else: 5 return "" if value == 0
  67. 5 then: 1 else: 4 return value.to_s if value < 0
  68. 4 return "\+#{value}"
  69. end
  70. end
  71. end
  72. end

lib/bcdice/game_system/DeadlineHeroes.rb

97.76% lines covered

92.11% branches covered

134 relevant lines. 131 lines covered and 3 lines missed.
38 total branches, 35 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/dice_table/range_table'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class DeadlineHeroes < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'DeadlineHeroes'
  8. # ゲームシステム名
  9. 1 NAME = 'デッドラインヒーローズRPG'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'てつとらいんひいろおすRPG'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・行為判定(DLHx)
  15.  x:成功率
  16.  例)DLH80
  17.  クリティカル、ファンブルの自動的判定を行います。
  18.  「DLH50+20-30」のように加減算記述も可能。
  19.  成功率は上限100%、下限0%
  20. ・デスチャート(DCxY)
  21.  x:チャートの種類。肉体:DCL、精神:DCS、環境:DCC
  22.  Y=マイナス値
  23.  例)DCL5:ライフが -5 の判定
  24.    DCS3:サニティーが -3 の判定
  25.    DCC0:クレジット 0 の判定
  26. ・ヒーローネームチャート(HNC)
  27. ・リアルネームチャート 日本(RNCJ)、海外(RNCO)
  28. INFO_MESSAGE_TEXT
  29. 1 register_prefix(
  30. 'DLH',
  31. 'DC[LSC]',
  32. 'RNC[JO]',
  33. 'HNC'
  34. )
  35. 1 def eval_game_system_specific_command(command)
  36. 112 case command
  37. when: 37 when /^DLH/i
  38. 37 resolute_action(command)
  39. when: 44 when /^DC\w/i
  40. 44 roll_death_chart(command)
  41. when: 15 when 'HNC'
  42. 15 roll_hero_name_chart()
  43. else: 16 else
  44. 16 roll_tables(command, TABLES)
  45. end
  46. end
  47. 1 private
  48. 1 def resolute_action(command)
  49. 37 m = /^DLH(\d+([+-]\d+)*)$/.match(command)
  50. 37 else: 37 then: 0 unless m
  51. return nil
  52. end
  53. 37 success_rate = ArithmeticEvaluator.eval(m[1])
  54. 37 roll_result, dice10, dice01 = roll_d100
  55. 37 roll_result_text = format('%02d', roll_result)
  56. 37 result = action_result(roll_result, dice10, dice01, success_rate)
  57. sequence = [
  58. 37 "行為判定(成功率:#{success_rate}%)",
  59. "1D100[#{dice10},#{dice01}]=#{roll_result_text}",
  60. roll_result_text.to_s,
  61. result.text
  62. ]
  63. 37 result.text = sequence.join(" > ")
  64. 37 result
  65. end
  66. 1 SUCCESS_STR = "成功"
  67. 1 FAILURE_STR = "失敗"
  68. 1 CRITICAL_STR = (SUCCESS_STR + " > クリティカル! パワーの代償1/2").freeze
  69. 1 FUMBLE_STR = (FAILURE_STR + " > ファンブル! パワーの代償2倍&振り直し不可").freeze
  70. 1 def action_result(total, tens, ones, success_rate)
  71. 37 then: 8 if total == 100 || success_rate <= 0
  72. 8 else: 29 Result.fumble(FUMBLE_STR)
  73. 29 then: 2 elsif total <= success_rate - 100
  74. 2 else: 27 Result.critical(CRITICAL_STR)
  75. 27 then: 8 elsif tens == ones
  76. 8 then: 6 if total <= success_rate
  77. 6 Result.critical(CRITICAL_STR)
  78. else: 2 else
  79. 2 Result.fumble(FUMBLE_STR)
  80. else: 19 end
  81. 19 then: 15 elsif total <= success_rate
  82. 15 Result.success(SUCCESS_STR)
  83. else: 4 else
  84. 4 Result.failure(FAILURE_STR)
  85. end
  86. end
  87. 1 def roll_d100
  88. 37 dice10 = @randomizer.roll_once(10)
  89. 37 then: 11 else: 26 dice10 = 0 if dice10 == 10
  90. 37 dice01 = @randomizer.roll_once(10)
  91. 37 then: 5 else: 32 dice01 = 0 if dice01 == 10
  92. 37 roll_result = dice10 * 10 + dice01
  93. 37 then: 7 else: 30 roll_result = 100 if roll_result == 0
  94. 37 return roll_result, dice10, dice01
  95. end
  96. 1 class DeathChart
  97. 1 def initialize(name, chart)
  98. 3 @name = name
  99. 3 @chart = chart.freeze
  100. 3 then: 0 else: 3 if @chart.size != 11
  101. raise ArgumentError, "unexpected chart size #{name.inspect} (given #{@chart.size}, expected 11)"
  102. end
  103. end
  104. # @param randomizer [Randomizer]
  105. # @param minus_score [Integer]
  106. # @return [String]
  107. 1 def roll(randomizer, minus_score)
  108. 44 dice = randomizer.roll_once(10)
  109. 44 key_number = dice + minus_score
  110. 44 key_text, chosen = at(key_number)
  111. 44 return "デスチャート(#{@name})[マイナス値:#{minus_score} + 1D10(->#{dice}) = #{key_number}] > #{key_text} : #{chosen}"
  112. end
  113. 1 private
  114. # key_numberの10から20がindexの0から10に対応する
  115. 1 def at(key_number)
  116. 44 then: 4 if key_number < 10
  117. 4 else: 40 ["10以下", @chart.first]
  118. 40 then: 3 elsif key_number > 20
  119. 3 ["20以上", @chart.last]
  120. else: 37 else
  121. 37 [key_number.to_s, @chart[key_number - 10]]
  122. end
  123. end
  124. end
  125. 1 def roll_death_chart(command)
  126. 44 m = /^DC([LSC])(\d+)$/i.match(command)
  127. 44 else: 44 then: 0 unless m
  128. return m
  129. end
  130. 44 chart = DEATH_CHARTS[m[1]]
  131. 44 minus_score = m[2].to_i
  132. 44 return chart.roll(@randomizer, minus_score)
  133. end
  134. DEATH_CHARTS = {
  135. 1 'L' => DeathChart.new(
  136. '肉体',
  137. [
  138. "何も無し。キミは奇跡的に一命を取り留めた。闘いは続く。",
  139. "激痛が走る。以後、イベント終了時まで、全ての判定の成功率-10%。",
  140. "キミは[硬直]ポイント2点を得る。[硬直]ポイントを所持している間、キミは「属性:妨害」のパワーを使用することができない。各ラウンド終了時、キミは所持している[硬直]ポイントを1点減らしてもよい。",
  141. "渾身の一撃!! キミは〈生存〉判定を行なう。失敗した場合、[死亡]する。",
  142. "キミは[気絶]ポイント2点を得る。[気絶]ポイントを所持している間、キミはあらゆるパワーを使用できず、自身のターンを得ることもできない。各ラウンド終了時、キミは所持している[気絶]ポイントを1点減らしてもよい。",
  143. "以後、イベント終了時まで、全ての判定の成功率-20%。",
  144. "記録的一撃!! キミは〈生存〉-20%の判定を行なう。失敗した場合、[死亡]する。",
  145. "キミは[瀕死]ポイント2点を得る。[瀕死]ポイントを所持している間、キミはあらゆるパワーを使用できず、自身のターンを得ることもできない。各ラウンド終了時、キミは所持している[瀕死]ポイントを1点を失う。全ての[瀕死]ポイントを失う前に戦闘が終了しなかった場合、キミは[死亡]する。",
  146. "叙事詩的一撃!! キミは〈生存〉-30%の判定を行なう。失敗した場合、[死亡]する。",
  147. "以後、イベント終了時まで、全ての判定の成功率-30%。",
  148. "神話的一撃!! キミは宙を舞って三回転ほどした後、地面に叩きつけられる。見るも無惨な姿。肉体は原型を留めていない(キミは[死亡]した)。",
  149. ]
  150. ),
  151. 'S' => DeathChart.new(
  152. '精神',
  153. [
  154. "何も無し。キミは歯を食いしばってストレスに耐えた。",
  155. "以後、イベント終了時まで、全ての判定の成功率-10%。",
  156. "キミは[恐怖]ポイント2点を得る。[恐怖]ポイントを所持している間、キミは「属性:攻撃」のパワーを使用できない。各ラウンド終了時、キミは所持している[恐怖]ポイントを1点減らしてもよい。",
  157. "とても傷ついた。キミは〈意志〉判定を行なう。失敗した場合、[絶望]してNPCとなる。",
  158. "キミは[気絶]ポイント2点を得る。[気絶]ポイントを所持している間、キミはあらゆるパワーを使用できず、自身のターンを得ることもできない。各ラウンド終了時、キミは所持している[気絶]ポイントを1点減らしてもよい。",
  159. "以後、イベント終了時まで、全ての判定の成功率-20%。",
  160. "信じるものに裏切られたような痛み。キミは〈意志〉-20%の判定を行なう。失敗した場合、[絶望]してNPCとなる。",
  161. "キミは[混乱]ポイント2点を得る。[混乱]ポイントを所持している間、キミは本来味方であったキャラクターに対して、可能な限り最大の被害を与える様、行動し続ける。各ラウンド終了時、キミは所持している[混乱]ポイントを1点減らしてもよい。",
  162. "あまりに残酷な現実。キミは〈意志〉-30%の判定を行なう。失敗した場合、[絶望]してNPCとなる。",
  163. "以後、イベント終了時まで、全ての判定の成功率-30%。",
  164. "宇宙開闢の理に触れるも、それは人類の認識限界を超える何かであった。キミは[絶望]し、以後NPCとなる。",
  165. ]
  166. ),
  167. 'C' => DeathChart.new(
  168. '環境',
  169. [
  170. "何も無し。キミは黒い噂を握りつぶした。",
  171. "以後、イベント終了時まで、全ての判定の成功率-10%。",
  172. "ピンチ! 以後、イベント終了時まで、キミは《支援》を使用できない。",
  173. "裏切り!! キミは〈経済〉判定を行なう。失敗した場合、キミはヒーローとしての名声を失い、[汚名]を受ける。",
  174. "以後、シナリオ終了時まで、代償にクレジットを消費するパワーを使用できない。",
  175. "キミの悪評は大変なもののようだ。協力者からの支援が打ち切られる。以後、シナリオ終了時まで、全ての判定の成功率-20%。",
  176. "信頼の失墜!! キミは〈経済〉-20%の判定を行なう。失敗した場合、キミはヒーローとしての名声を失い、[汚名]を受ける。",
  177. "以後、シナリオ終了時まで、【環境】系の技能のレベルがすべて0となる。",
  178. "捏造報道!! 身の覚えのない犯罪への荷担が、スクープとして報道される。キミは〈経済〉-30%の判定を行なう。失敗した場合、キミはヒーローとしての名声を失い、[汚名]を受ける。",
  179. "以後、イベント終了時まで、全ての判定の成功率-30%。",
  180. "キミの名は史上最悪の汚点として永遠に歴史に刻まれる。もはやキミを信じる仲間はなく、キミを助ける社会もない。キミは[汚名]を受けた。",
  181. ]
  182. )
  183. }.freeze
  184. 1 class RealNameChart < DiceTable::RangeTable
  185. 1 def initialize(name, columns, chart)
  186. 36 items = chart.map { |l| mix_column(columns, l) }
  187. 2 super(name, "1D100", items)
  188. end
  189. 1 private
  190. 1 def mix_column(columns, item)
  191. 34 range, names = item
  192. 34 then: 2 else: 32 if names.size == 1
  193. 2 return range, names[0]
  194. end
  195. 128 candidate = columns.zip(names).map { |l| "\n" + l.join(": ") }.join("")
  196. 32 return range, candidate
  197. end
  198. end
  199. TABLES = {
  200. 1 'RNCJ' => RealNameChart.new(
  201. 'リアルネームチャート(日本)',
  202. ['姓', '名(男)', '名(女)'],
  203. [
  204. [1..6, ['アイカワ/相川、愛川', 'アキラ/晶、章', 'アン/杏']],
  205. [7..12, ['アマミヤ/雨宮', 'エイジ/映司、英治', 'イノリ/祈鈴、祈']],
  206. [13..18, ['イブキ/伊吹', 'カズキ/和希、一輝', 'エマ/英真、恵茉']],
  207. [19..24, ['オガミ/尾上', 'ギンガ/銀河', 'カノン/花音、観音']],
  208. [25..30, ['カイ/甲斐', 'ケンイチロウ/健一郎', 'サラ/沙羅']],
  209. [31..36, ['サカキ/榊、阪木', 'ゴウ/豪、剛', 'シズク/雫']],
  210. [37..42, ['シシド/宍戸', 'ジロー/次郎、治郎', 'チズル/千鶴、千尋']],
  211. [43..48, ['タチバナ/橘、立花', 'タケシ/猛、武', 'ナオミ/直美、尚美']],
  212. [49..54, ['ツブラヤ/円谷', 'ツバサ/翼', 'ハル/華、波留']],
  213. [55..60, ['ハヤカワ/早川', 'テツ/鉄、哲', 'ヒカル/光']],
  214. [61..66, ['ハラダ/原田', 'ヒデオ/英雄', 'ベニ/紅']],
  215. [67..72, ['フジカワ/藤川', 'マサムネ/正宗、政宗', 'マチ/真知、町']],
  216. [73..78, ['ホシ/星', 'ヤマト/大和', 'ミア/深空、美杏']],
  217. [79..84, ['ミゾグチ/溝口', 'リュウセイ/流星', 'ユリコ/由里子']],
  218. [85..90, ['ヤシダ/矢志田', 'レツ/烈、裂', 'ルイ/瑠衣、涙']],
  219. [91..96, ['ユウキ/結城', 'レン/連、錬', 'レナ/玲奈']],
  220. [97..100, ['名無し(何らかの理由で名前を持たない、もしくは失った)']],
  221. ]
  222. ),
  223. 'RNCO' => RealNameChart.new(
  224. 'リアルネームチャート(海外)',
  225. ['名(男)', '名(女)', '姓'],
  226. [
  227. [1..6, ['アルバス', 'アイリス', 'アレン']],
  228. [7..12, ['クリス', 'オリーブ', 'ウォーケン']],
  229. [13..18, ['サミュエル', 'カーラ', 'ウルフマン']],
  230. [19..24, ['シドニー', 'キルスティン', 'オルセン']],
  231. [25..30, ['スパイク', 'グウェン', 'カーター']],
  232. [31..36, ['ダミアン', 'サマンサ', 'キャラダイン']],
  233. [37..42, ['ディック', 'ジャスティナ', 'シーゲル']],
  234. [43..48, ['デンゼル', 'タバサ', 'ジョーンズ']],
  235. [49..54, ['ドン', 'ナディン', 'パーカー']],
  236. [55..60, ['ニコラス', 'ノエル', 'フリーマン']],
  237. [61..66, ['ネビル', 'ハーリーン', 'マーフィー']],
  238. [67..72, ['バリ', 'マルセラ', 'ミラー']],
  239. [73..78, ['ビリー', 'ラナ', 'ムーア']],
  240. [79..84, ['ブルース', 'リンジー', 'リーヴ']],
  241. [85..90, ['マーヴ', 'ロザリー', 'レイノルズ']],
  242. [91..96, ['ライアン', 'ワンダ', 'ワード']],
  243. [97..100, ['名無し(何らかの理由で名前を持たない、もしくは失った)']],
  244. ]
  245. )
  246. }.freeze
  247. 1 def roll_hero_name_chart()
  248. 15 dice = @randomizer.roll_once(10)
  249. 15 template = HERO_NAME_TEMPLATES[dice - 1]
  250. 15 template_result = "ヒーローネームチャート(#{dice}) > #{template[:text]}"
  251. 15 then: 1 else: 14 if template[:text] == "任意"
  252. 1 return template_result
  253. end
  254. 14 results = [template_result]
  255. 14 elements = []
  256. 14 template[:elements].each do |type|
  257. 31 base_chart = HERO_NAME_BASE_CHARTS[type]
  258. 31 else: 28 then: 3 unless base_chart
  259. 3 elements.push(type)
  260. 3 next
  261. end
  262. 28 result, element = base_chart.roll(@randomizer)
  263. 28 results.push(result)
  264. 28 elements.push(element)
  265. end
  266. 14 hero_name = elements.join("").gsub(/・{2,}/, "・").sub(/・$/, "")
  267. 14 results.push("ヒーローネーム > #{hero_name}")
  268. 14 return results.join("\n")
  269. end
  270. HERO_NAME_TEMPLATES = [
  271. 1 {text: 'ベースA+ベースA', elements: ['ベースA', 'ベースB']},
  272. {text: 'ベースB', elements: ['ベースB']},
  273. {text: 'ベースB×2回', elements: ['ベースB', 'ベースB']},
  274. {text: 'ベースB+ベースC', elements: ['ベースB', 'ベースC']},
  275. {text: 'ベースA+ベースB+ベースC', elements: ['ベースA', 'ベースB', 'ベースC']},
  276. {text: 'ベースA+ベースB×2回', elements: ['ベースA', 'ベースB', 'ベースB']},
  277. {text: 'ベースB×2回+ベースC', elements: ['ベースB', 'ベースB', 'ベースC']},
  278. {text: '(ベースB)・オブ・(ベースB)', elements: ['ベースB', '・オブ・', 'ベースB']},
  279. {text: '(ベースB)・ザ・(ベースB)', elements: ['ベースB', '・ザ・', 'ベースB']},
  280. {text: '任意', elements: ['任意']},
  281. ].freeze
  282. 1 class HeroNameBaseChart
  283. 1 def initialize(name, items)
  284. 3 @name = name
  285. 3 @items = items
  286. end
  287. # @param randomizer [Randomizer]
  288. # @return [Array<(String, String)>]
  289. 1 def roll(randomizer)
  290. 28 dice = randomizer.roll_once(10)
  291. 28 chosen = @items[dice - 1]
  292. 28 result = "#{@name}(#{dice}) > #{chosen}"
  293. 28 then: 21 else: 7 if (m = chosen.match(/^[(.+)]$/))
  294. 21 element_type = m[1]
  295. 21 element_chart = HERO_NAME_ELEMENT_CHARTS[element_type]
  296. 21 element_result, chosen = element_chart.roll(randomizer)
  297. 21 result = [result, element_result].join(" > ")
  298. end
  299. 28 return result, chosen
  300. end
  301. end
  302. 1 class HeroNameElementChart
  303. 1 def initialize(name, items)
  304. 11 @name = name
  305. 11 @items = items
  306. end
  307. # @param randomizer [Randomizer]
  308. # @return [Array<(String, String)>]
  309. 1 def roll(randomizer)
  310. 21 dice = randomizer.roll_once(10)
  311. 21 chosen = @items[dice - 1]
  312. 21 result = "#{@name}(#{dice}) > #{chosen[:element]} (意味:#{chosen[:mean]})"
  313. 21 return result, chosen[:element]
  314. end
  315. end
  316. HERO_NAME_BASE_CHARTS = {
  317. 1 "ベースA" => HeroNameBaseChart.new(
  318. "ベースA",
  319. [
  320. "ザ・",
  321. "キャプテン・",
  322. "ミスター/ミス/ミセス・",
  323. "ドクター/プロフェッサー・",
  324. "ロード/バロン/ジェネラル・",
  325. "マン・オブ・",
  326. "[強さ]",
  327. "[色]",
  328. "マダム/ミドル・",
  329. "数字(1~10)・",
  330. ]
  331. ),
  332. "ベースB" => HeroNameBaseChart.new(
  333. "ベースB",
  334. [
  335. "[神話/夢]",
  336. "[武器]",
  337. "[動物]",
  338. "[鳥]",
  339. "[虫/爬虫類]",
  340. "[部位]",
  341. "[光]",
  342. "[攻撃]",
  343. "[その他]",
  344. "数字(1~10)・",
  345. ]
  346. ),
  347. "ベースC" => HeroNameBaseChart.new(
  348. "ベースC",
  349. [
  350. "マン/ウーマン",
  351. "ボーイ/ガール",
  352. "マスク/フード",
  353. "ライダー",
  354. "マスター",
  355. "ファイター/ソルジャー",
  356. "キング/クイーン",
  357. "[色]",
  358. "ヒーロー/スペシャル",
  359. "ヒーロー/スペシャル",
  360. ]
  361. ),
  362. }.freeze
  363. HERO_NAME_ELEMENT_CHARTS = {
  364. 1 "部位" => HeroNameElementChart.new(
  365. "部位",
  366. [
  367. {element: "ハート", mean: "心臓"},
  368. {element: "フェイス", mean: "顔"},
  369. {element: "アーム", mean: "腕"},
  370. {element: "ショルダー", mean: "肩"},
  371. {element: "ヘッド", mean: "頭"},
  372. {element: "アイ", mean: "眼"},
  373. {element: "フィスト", mean: "拳"},
  374. {element: "ハンド", mean: "手"},
  375. {element: "クロウ", mean: "爪"},
  376. {element: "ボーン", mean: "骨"},
  377. ]
  378. ),
  379. "武器" => HeroNameElementChart.new(
  380. "武器",
  381. [
  382. {element: "ナイヴス", mean: "短剣"},
  383. {element: "ソード", mean: "剣"},
  384. {element: "ハンマー", mean: "鎚"},
  385. {element: "ガン", mean: "銃"},
  386. {element: "スティール", mean: "刃"},
  387. {element: "タスク", mean: "牙"},
  388. {element: "ニューク", mean: "核"},
  389. {element: "アロー", mean: "矢"},
  390. {element: "ソウ", mean: "ノコギリ"},
  391. {element: "レイザー", mean: "剃刀"},
  392. ]
  393. ),
  394. "色" => HeroNameElementChart.new(
  395. "色",
  396. [
  397. {element: "ブラック", mean: "黒"},
  398. {element: "グリーン", mean: "緑"},
  399. {element: "ブルー", mean: "青"},
  400. {element: "イエロー", mean: "黃"},
  401. {element: "レッド", mean: "赤"},
  402. {element: "バイオレット", mean: "紫"},
  403. {element: "シルバー", mean: "銀"},
  404. {element: "ゴールド", mean: "金"},
  405. {element: "ホワイト", mean: "白"},
  406. {element: "クリア", mean: "透明"},
  407. ]
  408. ),
  409. "動物" => HeroNameElementChart.new(
  410. "動物",
  411. [
  412. {element: "バニー", mean: "ウサギ"},
  413. {element: "タイガー", mean: "虎"},
  414. {element: "シャーク", mean: "鮫"},
  415. {element: "キャット", mean: "猫"},
  416. {element: "コング", mean: "ゴリラ"},
  417. {element: "ドッグ", mean: "犬"},
  418. {element: "フォックス", mean: "狐"},
  419. {element: "パンサー", mean: "豹"},
  420. {element: "アス", mean: "ロバ"},
  421. {element: "バット", mean: "蝙蝠"},
  422. ]
  423. ),
  424. "神話/夢" => HeroNameElementChart.new(
  425. "神話/夢",
  426. [
  427. {element: "アポカリプス", mean: "黙示録"},
  428. {element: "ウォー", mean: "戦争"},
  429. {element: "エターナル", mean: "永遠"},
  430. {element: "エンジェル", mean: "天使"},
  431. {element: "デビル", mean: "悪魔"},
  432. {element: "イモータル", mean: "死なない"},
  433. {element: "デス", mean: "死神"},
  434. {element: "ドリーム", mean: "夢"},
  435. {element: "ゴースト", mean: "幽霊"},
  436. {element: "デッド", mean: "死んでいる"},
  437. ]
  438. ),
  439. "攻撃" => HeroNameElementChart.new(
  440. "攻撃",
  441. [
  442. {element: "ストローク", mean: "一撃"},
  443. {element: "クラッシュ", mean: "壊す"},
  444. {element: "ブロウ", mean: "吹き飛ばす"},
  445. {element: "ヒット", mean: "打つ"},
  446. {element: "パンチ", mean: "殴る"},
  447. {element: "キック", mean: "蹴る"},
  448. {element: "スラッシュ", mean: "斬る"},
  449. {element: "ペネトレイト", mean: "貫く"},
  450. {element: "ショット", mean: "撃つ"},
  451. {element: "キル", mean: "殺す"},
  452. ]
  453. ),
  454. "その他" => HeroNameElementChart.new(
  455. "その他",
  456. [
  457. {element: "ヒューマン", mean: "人間"},
  458. {element: "エージェント", mean: "代理人"},
  459. {element: "ブースター", mean: "泥棒"},
  460. {element: "アイアン", mean: "鉄"},
  461. {element: "サンダー", mean: "雷"},
  462. {element: "ウォッチャー", mean: "監視者"},
  463. {element: "プール", mean: "水たまり"},
  464. {element: "マシーン", mean: "機械"},
  465. {element: "コールド", mean: "冷たい"},
  466. {element: "サイド", mean: "側面"},
  467. ]
  468. ),
  469. "鳥" => HeroNameElementChart.new(
  470. "鳥",
  471. [
  472. {element: "ホーク", mean: "鷹"},
  473. {element: "ファルコン", mean: "隼"},
  474. {element: "キャナリー", mean: "カナリア"},
  475. {element: "ロビン", mean: "コマツグミ"},
  476. {element: "イーグル", mean: "鷲"},
  477. {element: "オウル", mean: "フクロウ"},
  478. {element: "レイブン", mean: "ワタリガラス"},
  479. {element: "ダック", mean: "アヒル"},
  480. {element: "ペンギン", mean: "ペンギン"},
  481. {element: "フェニックス", mean: "不死鳥"},
  482. ]
  483. ),
  484. "光" => HeroNameElementChart.new(
  485. "光",
  486. [
  487. {element: "ライト", mean: "光"},
  488. {element: "シャドウ", mean: "影"},
  489. {element: "ファイアー", mean: "炎"},
  490. {element: "ダーク", mean: "暗い"},
  491. {element: "ナイト", mean: "夜"},
  492. {element: "ファントム", mean: "幻影"},
  493. {element: "トーチ", mean: "灯火"},
  494. {element: "フラッシュ", mean: "閃光"},
  495. {element: "ランタン", mean: "手さげランプ"},
  496. {element: "サン", mean: "太陽"},
  497. ]
  498. ),
  499. "虫/爬虫類" => HeroNameElementChart.new(
  500. "虫/爬虫類",
  501. [
  502. {element: "ビートル", mean: "甲虫"},
  503. {element: "バタフライ/モス", mean: "蝶/蛾"},
  504. {element: "スネーク/コブラ", mean: "蛇"},
  505. {element: "アリゲーター", mean: "ワニ"},
  506. {element: "ローカスト", mean: "バッタ"},
  507. {element: "リザード", mean: "トカゲ"},
  508. {element: "タートル", mean: "亀"},
  509. {element: "スパイダー", mean: "蜘蛛"},
  510. {element: "アント", mean: "アリ"},
  511. {element: "マンティス", mean: "カマキリ"},
  512. ]
  513. ),
  514. "強さ" => HeroNameElementChart.new(
  515. "強さ",
  516. [
  517. {element: "スーパー/ウルトラ", mean: "超"},
  518. {element: "ワンダー", mean: "驚異的"},
  519. {element: "アルティメット", mean: "究極の"},
  520. {element: "ファンタスティック", mean: "途方もない"},
  521. {element: "マイティ", mean: "強い"},
  522. {element: "インクレディブル", mean: "凄い"},
  523. {element: "アメージング", mean: "素晴らしい"},
  524. {element: "ワイルド", mean: "狂乱の"},
  525. {element: "グレイテスト", mean: "至高の"},
  526. {element: "マーベラス", mean: "驚くべき"},
  527. ]
  528. ),
  529. }.freeze
  530. end
  531. end
  532. end

lib/bcdice/game_system/DemonParasite.rb

94.23% lines covered

82.35% branches covered

52 relevant lines. 49 lines covered and 3 lines missed.
17 total branches, 14 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class DemonParasite < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'DemonParasite'
  7. # ゲームシステム名
  8. 1 NAME = 'デモンパラサイト'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'てもんはらさいと'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・衝動表 (URGEx)
  14.  "URGE衝動レベル"の形で指定します。
  15.  衝動表に従って自動でダイスロールを行い、結果を表示します。
  16.  ダイスロールと同様に、他のプレイヤーに隠れてロールすることも可能です。
  17.  頭に識別文字を追加して、デフォルト以外の衝動表もロールできます。
  18.  ・NURGEx 頭に「N」を付けると「新衝動表」。
  19.  ・AURGEx 頭に「A」を付けると「誤作動表」。
  20.  ・MURGEx 頭に「M」を付けると「ミュータント衝動表」になります。
  21.  ・UURGEx 頭に「U」が付くと鬼御魂の戦闘外衝動表。
  22.  ・CURGEx 頭に「C」で鬼御魂の戦闘中衝動表になります。
  23. 例)URGE1   urge5   Surge2
  24. ・D66ダイスあり
  25. INFO_MESSAGE_TEXT
  26. 1 register_prefix('[NAMUC]?URGE')
  27. 1 def initialize(command)
  28. 248 super(command)
  29. 248 @sort_add_dice = true
  30. 248 @d66_sort_type = D66SortType::NO_SORT
  31. end
  32. # ゲーム別成功度判定(nD6)
  33. 1 def result_nd6(_total, _dice_total, dice_list, _cmp_op, target)
  34. 7 then: 2 if dice_list.count(1) >= 2 # 1の目が2個以上ならファンブル
  35. 2 else: 5 Result.fumble("致命的失敗")
  36. 5 then: 2 elsif dice_list.count(6) >= 2 # 6の目が2個以上あったらクリティカル
  37. 2 else: 3 Result.critical("効果的成功")
  38. 3 then: 1 else: 2 elsif target == "?"
  39. 1 Result.nothing
  40. end
  41. end
  42. 1 def eval_game_system_specific_command(command)
  43. 191 return get_urge(command)
  44. end
  45. # 衝動表
  46. 1 def get_urge(string)
  47. 91 m = /([NAMUC])?URGE\s*(\d+)/i.match(string)
  48. 91 else: 91 then: 0 unless m
  49. return '1'
  50. end
  51. 91 initialWord = m[1]
  52. 91 urgelv = m[2].to_i
  53. 91 case initialWord
  54. when: 40 when nil
  55. 40 title = "衝動表"
  56. 40 urge = URGE_TABLE
  57. when: 11 when "N"
  58. 11 title = "新衝動表"
  59. 11 urge = NEW_URGE_TABLE
  60. when: 10 when "A"
  61. 10 title = "誤作動表"
  62. 10 urge = MALFUNCTION_TABLE
  63. when: 10 when "M"
  64. 10 title = "ミュータント衝動表"
  65. 10 urge = MUTANT_TABLE
  66. when: 10 when "U"
  67. 10 title = "鬼御魂(戦闘外)衝動表"
  68. 10 urge = ONIMITAMA_OUT_OF_BATTLE_TABLE
  69. when: 10 when "C"
  70. 10 title = "鬼御魂(戦闘中)衝動表"
  71. 10 urge = ONIMITAMA_BATTLE_TABLE
  72. else
  73. else: 0 # あり得ない文字
  74. return '1'
  75. end
  76. 91 then: 0 else: 91 if urgelv < 1 || urgelv > 5
  77. return '衝動段階は1から5です'
  78. end
  79. 91 dice_now = @randomizer.roll_sum(2, 6)
  80. 91 resultText = urge[urgelv - 1][dice_now - 2]
  81. 91 return "#{title}#{urgelv}-#{dice_now}:#{resultText}"
  82. end
  83. # 衝動表
  84. URGE_TABLE = [
  85. 1 [
  86. '『怒り』突然強い怒りに駆られる。近くの対象に(非暴力の)怒りを全力でぶつける。このターンの終了まで「行動不能」となる。[経験値20点]',
  87. '『絶叫』寄生生物が体内で蠢く。その恐怖に絶叫。このターンの終了まで「行動不能」となる。[経験値10点]',
  88. '『悲哀』急に悲しいことを思い出して動きが止まる。このターンの終了まで「行動不能」となる。[経験値10点]',
  89. '『微笑』可笑しくてしょうがない。くすくす笑いが止まらず、このターンの終了まで「行動不能」となる。[経験値10点]',
  90. '『鈍感』衝動に気が付かなかった。何も起こらない。[経験値0点]',
  91. '『抑制』衝動を抑え込んだ。何も起こらない。[経験値0点]',
  92. '『我慢』衝動を我慢した。何も起こらない。[経験値0点]',
  93. '『前兆』悪魔的特徴が一瞬目立つ。1ターン(10秒)持続。変身中なら影響なし。[経験値10点]',
  94. '『発現』悪魔的特徴が急に目立つ。60ターン(10分)持続。変身中なら影響なし。[経験値10点]',
  95. '『変化』利き腕/前脚が2ターン(20秒)かけて悪魔化する。18ターン(3分)持続。変身中なら影響なし。[経験値20点]',
  96. '『顕現』利き腕/前脚が瞬時に悪魔化。60ターン(10分)持続。変身中なら影響なし。[経験値20点]',
  97. ],
  98. [
  99. '『茫然』思考が止まり、このターンの終了まで「攻撃」行動を行えない。回避行動に影響はない。[経験値20点]',
  100. '『激怒』側にいるもの(生物、物体問わず)が憎く、殴る。変身後ならば次のターンの終了まで、すべての命中判定+5、回避判定-5。[経験値20点]',
  101. '『残忍』殺意、破壊衝動が一瞬増す。戦闘中ならば次のターンに行われる「攻撃」行動の達成値に+5。[経験値20点]',
  102. '『落涙』過去の悲しい想い出が去来し、涙が溢れる。1ターン(10秒)「通常」行動を行えない。回避行動に影響はない。[経験値10点]',
  103. '『抑制』衝動を抑え込んだ。何も起こらない。[経験値0点]',
  104. '『我慢』衝動を我慢した。何も起こらない。[経験値0点]',
  105. '『忍耐』肉体を傷つけて衝動に耐えた。5ダメージ。[経験値10点]',
  106. '『辛抱』ほんの一瞬、全身が変身しかかる。無理に抑えたので、5ダメージ。変身中なら影響なし。[経験値10点]',
  107. '『異貌』3ターン(30秒)かけて顔が変身する。18ターン(3分)持続。変身中なら影響なし。[経験値20点]',
  108. '『苦痛』寄生生物が体内で暴れ、痛みにのけぞる。10ダメージ。[経験値20点]',
  109. '『変貌』変身後の(特異な)外見的特徴が3ターン(30秒)かけて現れる。18ターン(3分)持続。変身中なら影響なし。[経験値20点]',
  110. ],
  111. [
  112. '『憤怒』怒りに全身が満たされる。次のターンの終了まで、すべてのダメージのサイコロを+1個する。[経験値20点]',
  113. '『加速』ほとばしる衝動により。次のターンは【行動値】が2倍になる。[経験値20点]',
  114. '『発露』力が溢れ出る。次のターンの終了まで、すべてのダメージに+5、防御点-5(最低0)される。[経験値20点]',
  115. '『乾き』攻撃衝動を抑えられない。次のターンの終了まで全ての命中判定+5、回避判定-5。[経験値10点]',
  116. '『絶叫』あらん限りの声で叫ぶ。このターンの終了まで、全ての回避判定に-10。[経験値10点]',
  117. '『我慢』衝動を我慢した。何も起こらない。[経験値0点]',
  118. '『限界』衝動を無理矢理抑え込む。あちこちの血管が破裂し、10ダメージ。[経験値10点]',
  119. '『解放』衝動に耐えられず変身が始まる。3ターン(30秒)かけて変身。変身中なら影響なし。[経験値10点]',
  120. '『本能』衝動に駆られ、瞬時に変身。次のターン、目の前の動くものを敵味方区別無く攻撃する。[経験値20点]',
  121. '『保身』次のターンの終了まで、敵を攻撃できない。全ての防御力に+5。[経験値20点]',
  122. '『救済』悪魔寄生体が危機を察知し、【エナジー】を20点回復する。[経験値20点]',
  123. ],
  124. [
  125. '『癒し』衝動を1点使った回復を行う。[経験値20点]',
  126. '『離脱』その場から逃げ出す。逃げられない場合は、うずくまって動けなくなる。1ターン(10秒)経過すれば我に返る。[経験値20点]',
  127. '『脱力』急に力が抜ける。次のターンの終了まで、全ての判定に-5される。[経験値20点]',
  128. '『全力』激しい躁状態。次のターンの終了まで、命中判定に+10、回避判定に-10[経験値20点]',
  129. '『混沌』意味のある言葉を話せなくなる。1時間持続する。[経験値10点]',
  130. '『限界』衝動を無理矢理抑え込む。あちこちの血管が破裂し、10ダメージ。[経験値10点]',
  131. '『本能』衝動に駆られ、瞬時に変身。次のターン、目の前の動くものを敵味方区別無く攻撃する。[経験値20点]',
  132. '『焦燥』焦りから「転倒」する。[経験値20点]',
  133. '『猜疑』味方が急に敵に思える。即座に近くの味方に一回攻撃し、自動命中となる。いなければ影響なし。[経験値20点]',
  134. '『自虐』自分が許せない。自分へ攻撃(自動命中。ダメージは通常)。[経験値20点]',
  135. '『自浄』少し我に返る。衝動が2点回復する。[経験値20点]',
  136. ],
  137. [
  138. '『絶望』自殺を試みる。変身中ならば最強の攻撃(特殊能力等を使用しての攻撃)を自分へ与える。[経験値30点]',
  139. '『賛美』敵(複数いる場合はリーダー格)を主と思いこむ。主が倒されるか、このターンの終了まで主の命令を聞く。[経験値30点]',
  140. '『拒絶』変身が解除される。変身していなければ影響なし。[経験値20点]',
  141. '『飢餓』近くの無防備な対象を喰らおうとする。邪魔する物は敵として攻撃する。次ターンの終了時に我に返る。[経験値20点]',
  142. '『暗闇』視神経に影響が出る。以後1日「暗闇」になる。[経験値20点]',
  143. '『混乱』意味のある言葉を話せなくなる。1時間持続する。[経験値20点]',
  144. '『嫉妬』仲間に猛烈な嫉妬を覚える。即座に一番近くの味方を攻撃。判定は自動的に効果的成功となる。いなければ影響なし。[経験値20点]',
  145. '『暴君』自分が最強に思えてしかたがない。60ターン(10分)攻撃判定の達成値に+10、回避判定の達成値は-10。[経験値20点]',
  146. '『無双』全力だが無防備。60ターン(10分)、全てのダメージに+10、防御点0、【行動値】0。[経験値20点]',
  147. '『定着』変身していなければ、即座に変身。肉体が変身に馴染んでしまう。24時間、変身が解除されなくなる。[経験値30点]',
  148. '『眠り』猛烈な睡魔に襲われる。60ターン(10分)、もしくは戦闘終了まで起こしても起きない。[経験値30点]',
  149. ]
  150. ].freeze
  151. # 新衝動表
  152. NEW_URGE_TABLE = [
  153. 1 [
  154. '『開眼』潜在能力が発揮される。10分間、あらゆる戦闘以外の判定に+5。',
  155. '『集中』感覚が研ぎ澄まされる。次のターンの終了まで、射撃の命中判定に+5。',
  156. '『迅速』運動神経が上昇する。20分間、戦闘以外の【機敏】判定に+5。',
  157. '『怪力』怪力を発揮する。20分間、戦闘以外の【肉体】判定に+5。',
  158. '『鈍感』衝動に気が付かない。何も起こらない。',
  159. '『抑制』衝動を抑え込む。何も起こらない。',
  160. '『我慢』衝動を我慢する。何も起こらない。',
  161. '『無心』冷静になる。20分間、戦闘以外の【精神】判定に+5。',
  162. '『解放』感覚が解放される。20分間、戦闘以外の【感覚】判定に+5。',
  163. '『攻撃』攻撃の姿勢を取る。次のターンの終了まで、すべてのダメージが+5。',
  164. '『防御』防御の姿勢を取る。このターンの終了まで、すべての防御力が+5。',
  165. ],
  166. [
  167. '『敵視』激しい攻撃本能に駆られる。次のターンの終了まで、肉弾ダメージ+10。',
  168. '『忘我』怒りに痛みを忘れる。エナジー5点回復。',
  169. '『閃き』頭が冴える。20分間、戦闘以外の【知力】判定に+5。',
  170. '『全力』筋肉のリミッターが一時的にはずれる。次のターンの終了まで、肉弾ダメージに+5。',
  171. '『抑制』衝動を抑え込む。何も起こらない。',
  172. '『我慢』衝動を我慢する。何も起こらない。',
  173. '『反射』反射神経が研ぎ澄まされる。次のターンの終了まで、射撃の回避判定に+5。',
  174. '『機転』わずかなチャンスを見逃さなくなる。20分間、戦闘以外の【幸運】判定に+5。',
  175. '『耐性』精神力が上昇する。次のターンの終了まで、特殊防御力+5。',
  176. '『怒り』敵に対する怒りにとらわれる。次のターンの終了まで、肉弾の命中判定に+10。',
  177. '『活発』明るく活発になる。戦闘終了まで【行動値】+5。',
  178. ],
  179. [
  180. '『漲り』体の奥底から力がみなぎってくる。エナジー10点回復。',
  181. '『分析』相手の動きを冷静に分析できるようになる。5ターンの間、射撃ダメージに+10。',
  182. '『慈愛』万人に対して慈愛を感じるようになる。5ターンの間、回復に振るダイスが+1d。',
  183. '『慎重』敵の攻撃に慎重になる。次のターンの終了まで、すべての回避判定に+5。',
  184. '『本能』攻撃本能がむき出しになる。5ターンの間、特殊の命中判定に+5。',
  185. '『性急』気が早くなる。次のターンの終了まで、【行動値】に+3',
  186. '『凶暴』イライラが止まらなくなる。5ターンの間、肉弾の命中判定に+5。',
  187. '『楽観』気分がリラックスする。エナジー5点回復。',
  188. '『自閉』自分の殻に閉じこもろうとする。5ターンの間、特殊防御力に+5。',
  189. '『反射』敵の攻撃に即座に反応できる。5ターンの間、肉弾の回避判定に+10。',
  190. '『快感』快感を覚える。衝動が1点回復する。',
  191. ],
  192. [
  193. '『情熱』激しい情熱が噴き出してくる。エナジー10点と衝動1点回復。',
  194. '『気合』体中に気合いが入る。10ターンの間、すべてのダメージに+10。',
  195. '『加速』体中の神経が加速する。10ターンの間、すべての命中判定に+10。',
  196. '『利己』考え方が利己的になる。10ターンの間、特殊の命中判定に+10。',
  197. '『頑強』肉体が鋼のように強くなる。10ターンの間、肉弾防御力に+5。',
  198. '『察知』相手の動きを察知できる。10ターンの間、射撃防御力に+5。',
  199. '『殺意』激しい殺意にとらわれる。10ターンの間、特殊ダメージに+10。',
  200. '『静観』心が落ち着き冷静になる。10ターンの間、射撃の回避判定に+5。',
  201. '『是空』頭が冴えて敵の行動が読める。10ターンの間、すべての回避判定に+5。',
  202. '『心眼』心の目で相手の行動を読める。5ターンの間、射撃の回避判定に+10。',
  203. '『自愛』何をおいても自分が愛しく思える。5ターンの間、特殊の回避判定に+10。',
  204. ],
  205. [
  206. '『神速』人知を超えたスピードに目覚める。戦闘終了まで「通常」行動を2回行えるようになる。',
  207. '『流水』超感覚に目覚める。10ターンの間、すべての回避判定に+10。',
  208. '『覚醒』肉体の回復力が限界突破。エナジー20点回復。',
  209. '『忍耐』あらゆる苦痛に耐える鋼の精神が宿る。10ターンの間、すべての防御力に+5。',
  210. '『予知』第六感が研ぎ澄まされる。10ターンの間、射撃の命中とダメージに+10。',
  211. '『豪傑』身体能力が限界を超えて上昇する。10ターンの間、肉弾の命中とダメージに+10。',
  212. '『殺気』猛烈な殺意がみなぎる。10ターンの間、特殊の命中判定とダメージに+10。',
  213. '『発動』反射神経が飛躍的に加速される。10ターンの間、【行動値】+10。',
  214. '『激情』激しい感情があふれ出す。10ターンの間、すべてのダメージに+10。',
  215. '『超人』運動神経が飛躍的に加速される。10ターンの間、すべての命中判定に+15。',
  216. '『悟り』心が解放され無我の境地に達する。衝動が3点回復する',
  217. ]
  218. ].freeze
  219. # 誤作動表
  220. MALFUNCTION_TABLE = [
  221. 1 [
  222. '『緊急停止』機能に異常発生。次のターンの終了まで、「行動不能」になる。[30点]',
  223. '『動力不調』動力装置に異常発生。このターンの終了時まで、「行動不能」になる。[30点]',
  224. '『腕部停止』腕部機構に異常発生。このターンの終了時まで、「タイミング:攻撃」が行えない。[20点]',
  225. '『脚部停止』脚部機構に異常発生。このターンの終了時まで、あらゆる「移動」を行えない。[20点]',
  226. '『機能制動』機能が一瞬停止するが、影響なし。[10点]',
  227. '『不良調整』機能に違和感。影響なし。[10点]',
  228. '『機能安定』機能が安定した。影響なし。[10点]',
  229. '『機能暴発』直前に使用した《兵装》がこのターンの終了時まで使用不能。未使用なら影響なし。[20点]',
  230. '『離脱機能』機能の異常発生。行動を消費することなく、即座に敵から「移動(全力)」で離れる。[20点]',
  231. '『排熱暴走』排熱機能に異常発生。次のターン終了時まで「着火」状態となる。[30点]',
  232. '『作動予測』次に起きる誤作動を予測できる。「第2限界点」に達したとき、「作動予測」以外の任意の誤作動を選択できる。[30点]',
  233. ],
  234. [
  235. '『安全機能』安全機能が作動。このターンの終了時まで、あらゆる判定に-5。[40点]',
  236. '『筋肉萎縮』人工筋肉に異常発生。次のターン終了時まで、【肉体】判定に-2。[30点]',
  237. '『出力低下』駆動部に異常発生。次のターンの終了時まで、【機敏】判定に-2。[30点]',
  238. '『感覚異常』視界機能に異常発生。次のターンの終了時まで、【感覚】判定に-2。[20点]',
  239. '『視界不良』視界機能に異常発生。次のターンの終了時まで、【幸運】判定に-2。[20点]',
  240. '『機能制動』機能が一瞬停止するが、影響なし。[10点]',
  241. '『不良調整』機能に違和感。影響なし。[10点]',
  242. '『援護不通』援護ソフトが誤作動。次のターンの終了時まで、【知力】判定-2。[20点]',
  243. '『発声変調』発声機能に異常発生。次のターンの終了時まで、【精神】判定-2。[30点]',
  244. '『装甲軟化』防御機構に異常発生。あらゆる防御力に-5。[30点]',
  245. '『作動予測』次に起きる誤作動を予測できる。「第3限界点」に達したとき、「作動予測」以外の任意の誤作動を選択できる。[40点]',
  246. ],
  247. [
  248. '『動力漏電』動力から漏電。『負荷』が2点上昇。[40点]',
  249. '『駆動異常』脚部に異常発生。次のターンの終了時まで、「移動」距離半減。[40点]',
  250. '『足下転倒』バランサーに異常発生。「転倒」状態となる。[30点]',
  251. '『出力向上』《兵装》機能が向上。次のターンの終了時まで、特殊ダメージに+1d点。[30点]',
  252. '『機能制動』機能が一瞬停止するが、影響なし。[20点]',
  253. '『機能暴走』攻撃機能が暴走し、戦闘能力が上昇。「着火」状態になるが、あらゆるダメージに+10。[20点]',
  254. '『身体向上』格闘機能が向上。次のターンの終了時まで、肉弾ダメージに+1d点。[30点]',
  255. '『反射向上』反応速度が向上。次のターンの終了時まで、【行動値】が+5。[30点]',
  256. '『精度向上』標準機能が向上。次のターンの終了時まで、射撃ダメージに+1d点。[30点]',
  257. '『電子賦活』電磁障壁が突如回復。【電力】が10点回復する。[30点]',
  258. '『作動予測』次に起きる誤作動を予測できる。「第4限界点」に達したとき、「作動予測」以外の任意の誤作動を選択できる。[40点]',
  259. ],
  260. [
  261. '『照準誤認』照準機能に異常発生。即座に最も近い味方を全力攻撃。[50点]',
  262. '『攻撃特化』攻撃機能が上昇。次のターン終了時まで、あらゆるダメージに+2dされるが「タイミング:防御」を行えない。[40点]',
  263. '『機内窒息』呼吸補助機能に異常発生。次のターン終了時まで、「窒息」状態。[40点]',
  264. '『機能増強』全機能が飛躍的に向上。次のターン終了時まで、《兵装》のコストを払わなくて良い。[30点]',
  265. '『音声遮断』聴覚機能に異常発生。次のターン終了時まで、一切の物音が聞こえず、あらゆる回避判定に-5。[30点]',
  266. '『電流加速』電磁障壁が効率的に流れる。『負荷』が1点回復。[20点]',
  267. '『精密射撃』照準の精度が向上。あらゆるダメージに+5点。[30点]',
  268. '『電力浪費』電磁障壁が過剰に使用される。【電力】が10点減少。[30点]',
  269. '『荷電暴走』【電力】を5点消費するが、次のターン終了時まで、あらゆるダメージに+10点。[40点]',
  270. '『状況分析』視界機能が向上。あらゆる命中判定に+5。[40点]',
  271. '『作動予測』次に起きる誤作動を予測できる。「第5限界点」に達したとき、「作動予測」以外の任意の誤作動を選択できる。[50点]',
  272. ],
  273. [
  274. '『出力過剰』全出力が過剰。次のターン終了時まで、あらゆるダメージの総計が2倍になるが《兵装》のコストも2倍になる。[50点]',
  275. '『機関暴走』放熱機能が暴走。自分を中心に半径5m以内すべての対象を「着火」状態にする。[50点]',
  276. '『機体清冽』機能異常から復帰。「気絶」「死亡」を除く、あらゆる状態変化がすべて消滅。[40点]',
  277. '『鉄壁装甲』防御機能が向上。次のターン終了時まで、あらゆる防御力に+5。[30点]',
  278. '『緊急駆動』回避機能が向上。次のターン終了時まで、あらゆる回避判定に+5。[30点]',
  279. '『出力増大』装備補助機能が向上。次のターン終了時まで、「所持品」あるいは《兵装》を使用したダメージ総計が2倍になる。[30点]',
  280. '『機体加速』運動機能が暴走。次のターン終了時まで、【行動値】が2倍となる。[30点]',
  281. '『自動追尾』自動追尾機能が発動。次のターン終了時まで、あらゆる命中値に+5。[40点]',
  282. '『限定解除』全機能の限界を解除。次のターン終了時まで、あらゆるダメージに+10。[50点]',
  283. '『負荷軽減』急激に機体の負荷が低下。『負荷』が2点回復する。[50点]',
  284. '『複合反応』この表を2回振る。ただし、同じ結果が出た場合は適用するのは一度だけ。獲得経験値は累積する。[0点]',
  285. ]
  286. ].freeze
  287. # ミュータント衝動表
  288. MUTANT_TABLE = [
  289. 1 [
  290. '『怒り』突然強い怒りに駆られる。近くの対象にあたりちらす。このターンの終了まで「行動不能」となる。[20点]',
  291. '『絶叫』悪魔寄生体が蠢きだす。その恐怖に絶叫。このターンの終了まで「行動不能」となる。[10点]',
  292. '『悲哀』急に悲しいことを思い出す。このターンの終了まで「行動不能」となる。[10点]',
  293. '『微笑』可笑しくてしょうがない。くすくす笑いが止まらず、このターンの終了まで「行動不能」となる。[10点]',
  294. '『鈍感』衝動に気が付かなかった。何も起こらない。[0点]',
  295. '『抑制』衝動を抑え込んだ。何も起こらない。[0点]',
  296. '『我慢』衝動を我慢した。何も起こらない。[0点]',
  297. '『前兆』悪魔的特徴が一瞬目立つ。1ターン(10秒)持続。《擬態変化》を解いているなら影響なし。[10点]',
  298. '『発現』悪魔的特徴が急に目立つ。60ターン(10分)持続。《擬態変化》を解いているなら影響なし。[10点]',
  299. '『解除』利き腕/前脚の《擬態変化》が2ターン(20秒)かけて解除される。18ターン(3分)持続。《擬態変化》を解いているなら影響なし。[20点]',
  300. '『顕現』利き腕/前脚の《擬態変化》が瞬時に解除。60ターン(10分)持続。《擬態変化》を解いているなら影響なし。[20点]',
  301. ],
  302. [
  303. '『茫然』思考が止まり、このターンの終了まで「攻撃」行動を行えない。その他の行動は影響なし。[20点]',
  304. '『激怒』側にいるもの(生物、物体問わず)が憎くなり、殴る。《擬態変化》を解いているならば次のターンの終了まで、すべての命中判定+5、回避判定-5。[20点]',
  305. '『残忍』殺意、破壊衝動が一瞬増す。戦闘中ならば次のターンに行われる「攻撃」行動の達成値に+5。[20点]',
  306. '『落涙』過去の悲しい想い出が去来し、涙が溢れる。1ターン(10秒)「通常」行動を行えない。その他の行動に影響はない。[10点]',
  307. '『抑制』衝動を抑え込んだ。何も起こらない。[0点]',
  308. '『我慢』衝動を我慢した。何も起こらない。[0点]',
  309. '『忍耐』肉体を傷つけて衝動に耐えた。5点ダメージ。[10点]',
  310. '『辛抱』ほんの一瞬、《擬態変化》が解けかかる。無理に抑えたので5点ダメージ。《擬態変化》を解いているなら影響なし。[10点]',
  311. '『異貌』3ターン(30秒)かけて《擬態変化》が解除される。18ターン(3分)持続。《擬態変化》を解いているなら影響なし。[20点]',
  312. '『苦痛』寄生生物が体内で暴れ狂う。10点ダメージ。[20点]',
  313. '『変貌』特異な外見的特徴が3ターン(30秒)かけて現れる。18ターン(3分)持続。《擬態変化》を解いているなら影響なし。[20点]',
  314. ],
  315. [
  316. '『憤怒』怒りに全身が満たされる。次のターンの終了まで、すべてのダメージを+1d点する。[20点]',
  317. '『加速』ほとばしる衝動により。次のターンは【行動値】が2倍になる。[20点]',
  318. '『発露』力が溢れ出る。次のターンの終了まで、すべてのダメージに+5、防御点-5(最低0)される。[20点]',
  319. '『乾き』攻撃衝動を抑えられない。次のターンの終了まで全ての命中判定+5、回避判定-5。[10点]',
  320. '『絶叫』あらん限りの声で叫ぶ。このターンの終了まで、あらゆる回避判定に-10。[10点]',
  321. '『我慢』衝動を我慢した。何も起こらない。[0点]',
  322. '『限界』衝動を無理矢理抑え込む。10点ダメージ。[10点]',
  323. '『解放』衝動に耐えられず擬態が解ける。3ターン(30秒)かけて解除。《擬態変化》を解いているなら影響なし。[10点]',
  324. '『本能』衝動に駆られ、《擬態変化》が瞬時に解除。次のターンは、目の前の動くものを敵味方区別無く攻撃する。[20点]',
  325. '『保身』次のターンの終了まで、敵を攻撃できない。全ての防御力に+5。[20点]',
  326. '『救済』悪魔寄生体が危機を察知し、【エナジー】を20点回復する。[20点]',
  327. ],
  328. [
  329. '『癒し』【エナジー】が即座に3d点回復。[20点]',
  330. '『離脱』その場から逃げ出す。逃げられない場合は、うずくまって動けなくなる。1ターン(10秒)経過すれば我に返る。[20点]',
  331. '『脱力』急に力が抜ける。次のターンの終了まで、全ての判定に-5される。[20点]',
  332. '『全力』激しい躁状態。次のターンの終了まで、命中判定に+10、回避判定に-10。[20点]',
  333. '『混沌』1時間の間、意味のある言葉を話せなくなる。[10点]',
  334. '『争乱』体内で共生生物同士が争い、暴れ回る。衝動が1点増える。[10点]',
  335. '『本能』衝動に駆られ、《擬態変化》が瞬時に解除。次のターン、目の前の動くものを敵味方区別無く攻撃する。[20点]',
  336. '『焦燥』焦りから「転倒」する。[20点]',
  337. '『猜疑』味方が急に敵に思える。即座に近くの味方に1回攻撃(自動命中。ダメージは通常)。いなければ影響なし。[20点]',
  338. '『自虐』自分が許せない。自分へ素手攻撃(自動命中。ダメージは通常)。[20点]',
  339. '『自浄』少し我に返る。衝動が2点回復する。[20点]',
  340. ],
  341. [
  342. '『絶望』無力感にさいなまれる。次のターンの終了時まで「行動不能」となる。[30点]',
  343. '『眠り』猛烈な睡魔に襲われる。60ターン(10分)、もしくは戦闘終了まで起こしても起きない。[30点]',
  344. '『誤動』突然《擬態変化》が使用され、人間の姿になる(衝動も通常通り使用する)。既に使用していた場合は変化無し。[20点]',
  345. '『暗闇』視神経に影響が出る。以後1日「暗闇」になる。[20点]',
  346. '『再生』共生生物が危機を察知し、【エナジー】を10点回復する。[20点]',
  347. '『混乱』1時間の間、意味のある言葉を話せなくなる。[20点]',
  348. '『硬化』急に体が硬直する。このターンの終了時まで、あらゆる命中判定に-10、防御力に+10。[20点]',
  349. '『暴君』自分が最強に思えてしかたがない。60ターン(10分)攻撃判定に+10、回避判定に-10。[20点]',
  350. '『無双』全力だが無防備。60ターン(10分)、全てのダメージに+10、防御点と【行動値】は0。[20点]',
  351. '『喪失』《擬態変化》が使用中なら、即座に解除。さらに24時間、《擬態変化》が使えなくなる。[30点]',
  352. '『進化』共生生物たちが上手く混じって身体能力が向上する。次の判定の達成値+10。[30点]',
  353. ]
  354. ].freeze
  355. # 鬼御魂(戦闘外)衝動表
  356. ONIMITAMA_OUT_OF_BATTLE_TABLE = [
  357. 1 [
  358. '『恐怖』恐怖の感情が爆発し、目に映るすべてが恐ろしくなる。[20点]',
  359. '『落涙』過去の悲しい思い出が去来し、涙が溢れる。[10点]',
  360. '『哄笑』突如として精神が高揚し、狂ったように笑う。[10点]',
  361. '『咆哮』<和魂>によって怒りが増し、突如として雄たけびを上げる。[10点]',
  362. '『抑制』衝動を完全に律する。何も起こらない。[0点]',
  363. '『沈静』穏やかな気分になる。[0点]',
  364. '『理性』衝動を理性で押さえ込む。何も起こらない。[0点]',
  365. '『破裂』衝動を押さえ込もうとして体内の欠陥が破裂、喀血する。[10点]',
  366. '『喪失』一瞬、〈和魂〉の神通力が失われる。[10点]',
  367. '『枯渇』吸血への渇望が押さえられず、一般人を血走った目で見つめる。[10点]',
  368. '『内包』凄まじい勢いで体内に妖気が内包され、力が増す。[20点]',
  369. ],
  370. [
  371. '『飢餓』突然の吸血衝動。一般人を猛烈に襲いたくなる。[20点]',
  372. '『封印』妖気を操作できず、1分間《特殊能力》を使用できない。[20点]',
  373. '『拒絶』情緒が不安定となり、味方が急に怖くなる。[20点]',
  374. '『拡散』突如として全身から妖気が噴出、目の前の対象を吹き飛ばす。[10点]',
  375. '『抑制』衝動を完全に律する。なにも起こらない。[0点]',
  376. '『治癒』疲れが癒される。[0点]',
  377. '『本能』暴力衝動に駆られ、瞬時に"異形化"してしまう。[10点]',
  378. '『破砕』破壊衝動が巻き起こり、目の前の障害物を破壊する。[20点]',
  379. '『悪寒』突如として悪寒が走り、物事に集中できなくなる。',
  380. '『心傷』突如としてトラウマを思い出し、立ちつくす。[20点]',
  381. '『回想』過去の思い出が去来、活力がみなぎる。[30点]',
  382. ],
  383. [
  384. '『不動』妖気が全身を駆け巡り、激痛によって動けなくなる。[20点]',
  385. '『脱力』突如として妖気が衰え、脱力のあまり膝をつく。[20点]',
  386. '『異形』瞬時にして犬歯が肥大し、目が紅く、邪悪に輝く。[20点]',
  387. '『精密』突如として視界が広がり、目視せずとも背後の風景や人物を見通せる。[10点]',
  388. '『獰猛』突如として怒りの感情が湧き起こり、目前の対象を罵倒する。[0点]',
  389. '『高揚』〈和魂〉の影響により精神が高揚、躁状態となる。[0点]',
  390. '『憎悪』突如として憎悪が沸き起こり、目前の対象に掴みかかる。[0点]',
  391. '『加速』全身に妖気が駆け巡り、反射速度が増し、10秒を1分のように感じる。[10点]',
  392. '『平穏』精神に変調が起こり、異常なほど理性的になる。[20点]',
  393. '『慈愛』あらゆる者に自愛を抱き、親身に接する。[20点]',
  394. '『支配』一瞬〈和魂〉を完全支配、次に行う戦闘外の判定を1回だけ効果的成功する。[20点]',
  395. ],
  396. [
  397. '『変質』突如として妖気が変質、半径5mにわたって透明な壁を展開する。[30点]',
  398. '『増強』妖気によって身体能力が増強され、10分間[運動]上級を取得する。[20点]',
  399. '『拡大』妖気が目視できるほど両腕から発散、20m先の物体を操作できる。[20点]',
  400. '『清浄』妖気を開放、<鬼御魂>を持たない半径10m内全ての生物を眠らせる。[10点]',
  401. '『透視』濃密な妖気が瞳に宿り、1分間20mの距離を透視できる。[10点]',
  402. '『強行』突如として妖気が増し、接触した対象を【肉体】x2m吹き飛ばす。[0点]',
  403. '『衝撃』妖気が殺傷能力を帯び、接触した物体を破壊。20秒間、手足が簡易の肉弾武器となる。[10点]',
  404. '『撃滅』妖気が稲妻や火災へと変異し、接触した物体を「着火」させる。[20点]',
  405. '『展開』全身を包む妖気の層が厚くなり、1分間物理的な接触を行えない。[20点]',
  406. '『模倣』<和魂>が精神を活性化させ、異常な記憶力を手に入れる。[20点]',
  407. '『支配』一瞬<和魂>を完全支配、次に行う戦闘外の判定を1回だけ効果的成功する。[20点]',
  408. ],
  409. [
  410. '『解放』妖気を無尽蔵に解放、1分間、戦闘外で使用する「コスト」を無視できる。[30点]',
  411. '『加速』妖気が両足に集中、1分間、時速50kmで疾走できる。[20点]',
  412. '『付与』妖気が感覚に集中、1分間50m先を透視できる。[20点]',
  413. '『強固』妖気が全身に浸透、1分間「窒息」「状態変化」のダメージを無効。[20点]',
  414. '『破壊』全妖気が膂力に変換され、1分間【肉体】判定の達成値を2倍にする。[20点]',
  415. '『爆散』1分間妖気が変質、接触した対象を爆破でき、障害物を瞬時に破壊。[10点]',
  416. '『浄化』半径10m全てを浄化、範囲内で持続する《特殊能力》の効果を無効化。[20点]',
  417. '『律動』半径10m内の<鬼御魂>を持たない生物を1分間気絶させる。[20点]',
  418. '『修復』妖気が極限まで活性化され、疲労を取り払う。[20点]',
  419. '『本性』瞬時に異形化。異形化中であれば、さらに禍々しい姿へ変質する。[20点]',
  420. '『覚醒』1時間、全身から閃光を発し、高さが【精神】mの"光の柱"に包まれる。[30点]',
  421. ]
  422. ].freeze
  423. # 鬼御魂(戦闘中)衝動表
  424. ONIMITAMA_BATTLE_TABLE = [
  425. 1 [
  426. '『恐怖』効果が発生したターンの終了時まで「行動不能」状態となる。',
  427. '『落涙』1ターン(10秒)「通常」行動を行えない。回避行動に影響はない。',
  428. '『哄笑』効果が発生したターンの終了時まで「行動不能」となる。',
  429. '『咆哮』効果が発生したターンの終了時まで「行動不能」となる。',
  430. '『抑制』影響なし。',
  431. '『沈静』【エナジー】を3点回復する。',
  432. '『理性』影響なし。',
  433. '『破裂』【エナジー】が5点減少する。',
  434. '『喪失』次ターンの【行動値】が半減(端数切捨て)。',
  435. '『枯渇』次ターンの終了時まで、あらゆるダメージに「+2」点。',
  436. '『内包』『衝動』が2点回復する。',
  437. ],
  438. [
  439. '『飢餓』最も近くの無防備な対象から血液摂取を試みる。対象が<鬼御魂>を持たない場合、血液採取の効果を得られる。',
  440. '『封印』効果が発生したターンの終了時まで《特殊能力》を使用できない。',
  441. '『拒絶』効果が発生したターンの終了時まで、味方を対象とした《特殊効果》を使用不可。',
  442. '『拡散』半径5m以内の対象全ての【エナジー】を1d点減少する(抵抗不可、防御力無視)。',
  443. '『抑制』影響なし。',
  444. '『治癒』【エナジー】を5点回復する。',
  445. '『本能』即座に"異形化"、ターン終了まで任意のダメージ1つに「+1d」点。',
  446. '『破砕』行動を消費することなく、近くに存在する障害物1つを瞬時に破壊。',
  447. '『悪寒』効果が発生したターンの終了時まで、あらゆる判定の達成値に「-5」。',
  448. '『心傷』効果が発生したターンの終了時まで、「タイミング:攻撃」を行えない。',
  449. '『回想』『衝動』を3点回復する。',
  450. ],
  451. [
  452. '『不動』次のターンの終了時まで「タイミング:通常」を行えない。',
  453. '『脱力』次のターンの終了時まで「転倒」状態となる。',
  454. '『異形』次に行う行為判定は、出目に関係なく効果的成功として扱う。',
  455. '『精密』次のターンの終了時まで、射撃ダメージに「+5」点。',
  456. '『獰猛』次のターンの終了時まで、肉弾ダメージに「+5」点。',
  457. '『高揚』次のターンの終了時まで、あらゆるダメージに「+1d」点。',
  458. '『憎悪』次のターンの終了時まで、特殊ダメージに「+5」点。',
  459. '『加速』次のターンの終了時まで【行動値】に「+5」。',
  460. '『平穏』あらゆる「状態変化」を任意で1つ消滅させる。',
  461. '『慈愛』半径5m内の味方全ての【エナジー】を5点回復する。',
  462. '『支配』「衝動表」の結果を、第三段階の中から任意のものから1つ選択できる。',
  463. ],
  464. [
  465. '『変質』次のターンの終了時まで、任意の防御力の1つに「+10」点。',
  466. '『増強』次のターンの終了時まで、任意の回避判定1つに「+5」。',
  467. '『拡大』次のターンの終了時まで、任意の命中判定1つに「+5」。',
  468. '『清浄』半径10m内の味方全ての【エナジー】を5点回復する。',
  469. '『透視』次のターン終了時まで、射撃ダメージに「+10」点。',
  470. '『強行』次のターンは、「タイミング:攻撃」を余分に1回行うことができる。',
  471. '『衝撃』次のターンの終了時まで、肉弾ダメージに「+10」点。',
  472. '『撃滅』次のターンの終了時まで、特殊ダメージに「+10」点。',
  473. '『展開』次のターンの終了時まで、本人が受けるあらゆるダメージを半減できる。',
  474. '『模倣』次のターンの終了時まで、敵が使用した《特殊能力》1つを1回だけ使用可能。',
  475. '『支配』「衝動表」の結果を、第四段階の中から任意のものから1つ選択できる。',
  476. ],
  477. [
  478. '『解放』次のターンの終了時まで、あらゆる戦闘修正が2倍となる。',
  479. '『加速』次のターンの終了時まで、【行動値】が2倍となる。',
  480. '『付与』次のターンの終了時まで、射撃ダメージの総計を2倍にできる。',
  481. '『強固』次のターンの終了時まで、あらゆる防御力に「+10」点。',
  482. '『破壊』次のターンの終了時まで、肉弾ダメージの総計を2倍にできる。',
  483. '『爆散』次のターンの終了時まで、あらゆるダメージに「+2d」点。',
  484. '『浄化』『衝動』を1d点回復する。',
  485. '『律動』次のターンの終了時まで、特殊ダメージの総計を2倍にできる。',
  486. '『修復』【エナジー】が最大値まで回復する。',
  487. '『本性』この戦闘中のみ、最終能力を2回使用できる。',
  488. '『覚醒』第五段階を2回振り、双方の効果を適応する。',
  489. ]
  490. ].freeze
  491. end
  492. end
  493. end

lib/bcdice/game_system/DemonSpike.rb

97.73% lines covered

90.91% branches covered

44 relevant lines. 43 lines covered and 1 lines missed.
11 total branches, 10 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class DemonSpike < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'DemonSpike'
  7. # ゲームシステム名
  8. 1 NAME = 'デモンスパイク'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'てもんすはいく'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・行為判定 xDS+y
  14.  行為判定を行い、達成値、成否、成功度を出力する。
  15.  x: ダイス数(省略:2)
  16.  y: 能力値やスパイク能力による達成値の修正(省略可)
  17. INFO_MESSAGE_TEXT
  18. 1 register_prefix('\d*DS')
  19. 1 def eval_game_system_specific_command(command)
  20. 12 roll_action(command)
  21. end
  22. 1 private
  23. 1 def roll_action(command)
  24. 12 parser = Command::Parser.new("DS", round_type: @round_type)
  25. .enable_prefix_number
  26. .restrict_cmp_op_to(nil)
  27. 12 parsed = parser.parse(command)
  28. 12 else: 12 then: 0 unless parsed
  29. return nil
  30. end
  31. 12 parsed.prefix_number ||= 2
  32. 12 then: 1 else: 11 if parsed.prefix_number < 2
  33. 1 return nil
  34. end
  35. 11 step = roll_step(parsed.prefix_number)
  36. 11 step_list = [step]
  37. 11 body: 7 while step[:dice_sum] == 10
  38. 7 step = roll_step(parsed.prefix_number)
  39. 7 step_list.push(step)
  40. end
  41. 11 is_fumble = step_list[0][:dice_sum] == 2
  42. 27 then: 2 else: 9 total = is_fumble ? 0 : step_list.sum { |s| s[:dice_sum] } + parsed.modify_number
  43. 11 success_level = total / 10
  44. 11 is_success = total >= 10
  45. res =
  46. 11 then: 7 if is_success
  47. 7 else: 4 "成功, 成功度#{success_level}"
  48. 4 then: 2 elsif is_fumble
  49. 2 "自動的失敗"
  50. else: 2 else
  51. 2 "失敗"
  52. end
  53. sequence = [
  54. 11 "(#{parsed})",
  55. 18 step_list.map { |s| "#{s[:dice_sum]}[#{s[:dice_list].join(',')}]" },
  56. total,
  57. res,
  58. ].flatten
  59. 11 return Result.new.tap do |r|
  60. 11 r.condition = is_success
  61. 11 r.critical = step_list.length > 1
  62. 11 r.fumble = is_fumble
  63. 11 r.text = sequence.join(" > ")
  64. end
  65. end
  66. 1 def roll_step(times)
  67. 18 dice_list = @randomizer.roll_barabara(times, 6).sort.reverse
  68. 18 dice_sum = (dice_list[0] + dice_list[1]).clamp(2, 10)
  69. 18 return {dice_list: dice_list, dice_sum: dice_sum}
  70. end
  71. end
  72. end
  73. end

lib/bcdice/game_system/DesperateRun.rb

100.0% lines covered

100.0% branches covered

42 relevant lines. 42 lines covered and 0 lines missed.
12 total branches, 12 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/base"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class DesperateRun < Base
  6. # ゲームシステムの識別子
  7. 1 ID = "DesperateRun"
  8. # ゲームシステム名
  9. 1 NAME = "Desperate Run TRPG"
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = "てすへれいとらんTRPG"
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・難易度算出コマンド DDC
  15. ・判定コマンド RCx or RCx+y or RCx-y(x=難易度、y=修正値(省略可能))
  16. ・アクシデント表 ACT
  17. ・初期アイテム表 ITEMT
  18. ・動機表 DOUKIT
  19. ・死亡フラグ台詞表 FLAGT
  20. ・途中参加動機表 ENTRYT
  21. ・途中参加道中表 ROADT
  22. INFO_MESSAGE_TEXT
  23. TABLES = {
  24. 1 "ACT" => DiceTable::Table.new(
  25. "アクシデント表",
  26. "1D6", [
  27. "PC全員、隊列を1D6で決める(12:前列、34:中列、56:後列)",
  28. "1ターン、モンスター側のみ行動する。",
  29. "この戦闘の行動順が、PC→モンスター、から、モンスター→PCに変わる。",
  30. "PC全員、アイテム1つを選んで失う。",
  31. "PC全員1D6を振る。この戦闘中、その出目はノープランになる。",
  32. "PC全員、Flagが1増加する。"
  33. ]
  34. ),
  35. "ITEMT" => DiceTable::Table.new(
  36. "初期アイテム表",
  37. "2D6", [
  38. "ロケットランチャー 効果:(装備)マカブルLv+3 回数:攻撃1回",
  39. "キーピック 効果:(消費)ムーブシーンで使用可。判定の出目の合計+1 回数:2回",
  40. "レーダー 効果:(装備)ノープラン 装備時、「危険」を1減らすことが出来る 回数:危険減少2回",
  41. "食料 効果:(消費)ムーブシーンで使用可。Life3回復 回数:1回",
  42. "応急キット 効果:(装備)メディカルLv+1 回数:回復3回",
  43. "刃物 効果:(装備)アタックLv+1 回数:攻撃6回",
  44. "銃 効果:(装備)シュートLv+1 回数:攻撃6回",
  45. "ドラッグ 効果:(消費)いつでも使用可。Brave1回復 回数:1回",
  46. "金券 効果:(消費)アフタープレイで使用可。経験点+2 回数:1回",
  47. "プロテクター 効果:(装備)ガードLv+1 回数:防御5回",
  48. "トミーガン 効果:(装備)チェーンLv+5 回数:攻撃1回"
  49. ]
  50. ),
  51. "DOUKIT" => DiceTable::Table.new(
  52. "動機表",
  53. "1D6", [
  54. "隷属。何か弱みに付け込まれ、嫌々ながらも参加することとなる。後ろめたい事、借金、など。",
  55. "献身。この番組は誰かのために出ている。病気の家族を救うため、参加者の一人が恋人である、など。",
  56. "成行。望んでいないのに参加することとなってしまった。誰かが勝手に申し込んだ、紛れ込んでしまった、など。",
  57. "渇望。とにかく何かを欲して参加している。金、スリル、金で手に入るもの、など。",
  58. "奇人。好き好んでこの番組に出ている。殺人癖、ナルシスト、自殺願望、化け物マニア、など。",
  59. "仕事。この番組に出るのは仕事だからだ。賞金稼ぎ、芸能人、記者、番組スタッフ、など。"
  60. ]
  61. ),
  62. "FLAGT" => DiceTable::Table.new(
  63. "死亡フラグ台詞表",
  64. "1D6", [
  65. "希望。「これが終わったら、一緒に酒でも飲もうや」「もう何も怖くない」など。",
  66. "望郷。「くそっ、、、俺には、帰りを待つ人が、、、っ!」「ああ、故郷のマルゲリータをもう一度食べたかった、、、」など。",
  67. "狂乱。「お前を、殺せば、俺は、億万長者なんだよぉぉぉお!!」「ヒハッ、死ね死ね死ね死ねぇぇぇぇ」など。",
  68. "絶望。「もうだめだぁ、、、おしまいだぁ、、、」「く、くるなっ、くるなぁぁぁぁ!!」など。",
  69. "慢心。「なんだ、こんなやつ、俺だけで十分だ」「大丈夫だ、問題ない」など。",
  70. "犠牲。「ふふ、俺なら大丈夫だ、、、気にするな」「お前ら下がれっ!ここは俺に任せろ!」など。"
  71. ]
  72. ),
  73. "ENTRYT" => DiceTable::Table.new(
  74. "途中参加動機表",
  75. "1D6", [
  76. "遅刻。もともと参加する予定だったのだが遅れてしまった。今からでも走れと無理矢理参加。",
  77. "現住。もともとここに住んでいた。何?番組?え?あ、お金もらえんの?イイネ!",
  78. "突発。もともと視聴者としてスタジオに居たんだけど、司会にうまく乗せられて・・・",
  79. "乱入。何か目的があって乱入した。今回のステージが簡単に見えたり、参加者に大事な人がいたのかもしれない。",
  80. "神隠。今回より前の番組に参加していたが行方不明・死んだと思われていた。が。君はまだここにいる。",
  81. "職員。あれ、逃げ遅れました?あらあら、大変ですね、しょうがないから参加者さんと一緒に走ってください。"
  82. ]
  83. ),
  84. "ROADT" => DiceTable::Table.new(
  85. "途中参加道中表",
  86. "1D6", [
  87. "死線。死ぬかと思った。Flag+1",
  88. "怪我。痛い。Life-1",
  89. "失意。どうしてこうなった。Brave-1。減らせない場合、Flag+1",
  90. "紛失。どっかいった。Itemをどれか1つ捨てる。捨てれない場合、Flag+1",
  91. "追尾。後ろ!後ろーっ!参加開始部屋の危険+1",
  92. "迷子。あれ、ここどこだ?途中参加道中表を振る回数+2"
  93. ]
  94. )
  95. }.freeze
  96. 1 register_prefix('RC', 'DDC', TABLES.keys)
  97. 1 def initialize(command)
  98. 77 super(command)
  99. 77 @sort_add_dice = true
  100. 77 @d66_sort_type = D66SortType::ASC
  101. end
  102. 1 private
  103. 1 def eval_game_system_specific_command(command)
  104. 76 check_roll(command) || ddc_table(command) || roll_tables(command, self.class::TABLES)
  105. end
  106. 1 def check_roll(string)
  107. 76 parser = Command::Parser.new(/RC\d+/, round_type: round_type)
  108. .restrict_cmp_op_to(nil)
  109. 76 cmd = parser.parse(string)
  110. 76 else: 16 then: 60 return nil unless cmd
  111. 16 d1, d2 = @randomizer.roll_barabara(2, 6)
  112. 16 dice_total = d1 + d2
  113. 16 total = d1 + d2 + cmd.modify_number
  114. 16 target = cmd.command[2..-1].to_i
  115. 16 then: 8 else: 8 modifier_str = " 修正値:#{cmd.modify_number}" if cmd.modify_number != 0
  116. result =
  117. 16 then: 4 if d1 == d2
  118. 4 else: 12 Result.critical("ゾロ目!【Critical】")
  119. 12 then: 4 elsif dice_total == 7
  120. 4 else: 8 Result.fumble("ダイスの出目が表裏!【Fumble】")
  121. 8 then: 4 elsif total >= target
  122. 4 Result.success("#{total}、難易度以上!【Success】")
  123. else: 4 else
  124. 4 Result.failure("#{total}、難易度未満!【Miss】")
  125. end
  126. sequence = [
  127. 16 "判定 難易度:#{target}#{modifier_str}",
  128. "出目:#{d1}、#{d2}",
  129. result.text,
  130. ]
  131. 16 result.text = sequence.join(" > ")
  132. 16 result
  133. end
  134. 1 def ddc_table(command)
  135. 60 then: 48 else: 12 return nil if command != "DDC"
  136. 12 d1, d2 = @randomizer.roll_barabara(2, 6)
  137. 12 smaller, larger = [d1, d2].sort
  138. 12 difference = larger - smaller
  139. 12 "難易度決定 > 出目:#{d1}、#{d2} > #{larger}-#{smaller}=#{difference} > 難易度#{5 + difference}"
  140. end
  141. end
  142. end
  143. end

lib/bcdice/game_system/DetatokoSaga.rb

98.18% lines covered

92.68% branches covered

110 relevant lines. 108 lines covered and 2 lines missed.
41 total branches, 38 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class DetatokoSaga < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'DetatokoSaga'
  7. # ゲームシステム名
  8. 1 NAME = 'でたとこサーガ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'てたとこさあか'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・通常判定 xDS or xDSy or xDS>=t or xDSy>=t or xDS+z>=t or xDSy+z>=t
  14.  (x=スキルランク、y=現在フラグ値(省略時0)、z=修正値(省略時0)、t=目標値(省略時8))
  15.  例)3DS 2DS5 0DS 3DS>=10 3DS7>=12 2DS3+1 3DS2+1>=10
  16. ・判定値 xJD or xJDy or xJDy+z or xJDy-z or xJDy/z
  17.  (x=スキルランク、y=現在フラグ値(省略時0)、z=修正値(省略時0))
  18.  例)3JD 2JD5 3JD7+1 4JD/3
  19. ・体力烙印表 SST (StrengthStigmaTable)
  20. ・気力烙印表 WST (WillStigmaTable)
  21. ・体力バッドエンド表 SBET (StrengthBadEndTable)
  22. ・気力バッドエンド表 WBET (WillBadEndTable)
  23. INFO_MESSAGE_TEXT
  24. 1 register_prefix('\d+DS', '\d+JD')
  25. 1 def initialize(command)
  26. 88 super(command)
  27. 88 @sort_add_dice = true
  28. 88 @d66_sort_type = D66SortType::ASC
  29. end
  30. 1 def eval_game_system_specific_command(command)
  31. 88 debug("eval_game_system_specific_command begin string", command)
  32. 88 result = checkRoll(command)
  33. 88 then: 34 else: 54 return result if result
  34. 54 result = checkJudgeValue(command)
  35. 54 then: 34 else: 20 return result if result
  36. 20 debug("各種表として処理")
  37. 20 return roll_tables(ALIAS[command] || command, self.class::TABLES)
  38. end
  39. # 通常判定 xDS or xDSy or xDS>=z or xDSy>=z
  40. 1 def checkRoll(string)
  41. 88 debug("checkRoll begin string", string)
  42. 88 m = %r{^(\d+)DS(\d+)?(([+-/])(\d+))?(?:>=(\d+))?$}i.match(string)
  43. 88 else: 34 then: 54 unless m
  44. 54 return nil
  45. end
  46. 34 skill = m[1].to_i
  47. 34 flag = m[2].to_i
  48. 34 operator = m[4]
  49. 34 value = m[5].to_i
  50. 34 then: 12 else: 22 target = m[6]&.to_i || 8
  51. 34 result = translate("DetatokoSaga.DS.input_options", skill: skill, flag: flag, target: target)
  52. 34 modifyText = getModifyText(operator, value)
  53. 34 else: 20 then: 14 result += translate("DetatokoSaga.DS.modifier", modifier: modifyText) unless modifyText.empty?
  54. 34 total, rollText = getRollResult(skill)
  55. 34 result += " > #{total}[#{rollText}]#{modifyText}"
  56. 34 totalResult = getTotalResultValue(total, value, operator)
  57. 34 result += " > #{totalResult}"
  58. 34 else: 20 then: 14 unless modifyText.empty?
  59. 14 else: 0 case operator
  60. when: 14 when "+"
  61. 14 total += value
  62. when: 0 when "-"
  63. total -= value
  64. end
  65. end
  66. 34 success = getSuccess(total, target)
  67. 34 result += " > #{success}"
  68. 34 result += getCheckFlagResult(total, flag)
  69. 34 return result
  70. end
  71. 1 def getRollResult(skill)
  72. 68 diceCount = skill + 1
  73. 68 then: 4 else: 64 diceCount = 3 if skill == 0
  74. 68 dice = @randomizer.roll_barabara(diceCount, 6)
  75. 68 diceText = dice.join(',')
  76. 68 dice = dice.sort
  77. 68 then: 64 else: 4 dice = dice.reverse if skill != 0
  78. 68 total = dice[0] + dice[1]
  79. 68 return total, diceText
  80. end
  81. 1 def getSuccess(check, target)
  82. 34 then: 16 if check >= target
  83. 16 translate("DetatokoSaga.DS.success")
  84. else: 18 else
  85. 18 translate("DetatokoSaga.DS.failure")
  86. end
  87. end
  88. 1 def getCheckFlagResult(total, flag)
  89. 68 then: 44 else: 24 if total > flag
  90. 44 return ""
  91. end
  92. 24 will = getDownWill(flag)
  93. 24 return translate("DetatokoSaga.less_than_flag", will: will)
  94. end
  95. 1 def getDownWill(flag)
  96. 24 then: 6 else: 18 if flag >= 10
  97. 6 return "6"
  98. end
  99. 18 dice = @randomizer.roll_once(6)
  100. 18 return "1D6->#{dice}"
  101. end
  102. # スキル判定値 xJD or xJDy or xJDy+z or xJDy-z or xJDy/z
  103. 1 def checkJudgeValue(string)
  104. 54 debug("checkJudgeValue begin string", string)
  105. 54 m = %r{^(\d+)JD(\d+)?(([+-/])(\d+))?$}i.match(string)
  106. 54 else: 34 then: 20 unless m
  107. 20 return nil
  108. end
  109. 34 skill = m[1].to_i
  110. 34 flag = m[2].to_i
  111. 34 operator = m[4]
  112. 34 value = m[5].to_i
  113. 34 result = translate("DetatokoSaga.JD.input_options", skill: skill, flag: flag)
  114. 34 modifyText = getModifyText(operator, value)
  115. 34 else: 18 then: 16 result += translate("DetatokoSaga.JD.modifier", modifier: modifyText) unless modifyText.empty?
  116. 34 total, rollText = getRollResult(skill)
  117. 34 result += " > #{total}[#{rollText}]#{modifyText}"
  118. 34 totalResult = getTotalResultValue(total, value, operator)
  119. 34 result += " > #{totalResult}"
  120. 34 result += getCheckFlagResult(total, flag)
  121. 34 return result
  122. end
  123. 1 def getModifyText(operator, value)
  124. 68 then: 38 else: 30 return '' if value == 0
  125. operatorText =
  126. 30 case operator
  127. when: 16 when "+"
  128. 16 "+"
  129. when: 2 when "-"
  130. 2 "-"
  131. when: 12 when "/"
  132. 12 "÷"
  133. else: 0 else
  134. return ""
  135. end
  136. 30 return "#{operatorText}#{value}"
  137. end
  138. 1 def getTotalResultValue(total, value, operator)
  139. 68 case operator
  140. when: 16 when "+"
  141. 16 return "#{total}+#{value} > " + translate("DetatokoSaga.total_value", total: total + value)
  142. when: 2 when "-"
  143. 2 return "#{total}-#{value} > " + translate("DetatokoSaga.total_value", total: total - value)
  144. when: 14 when "/"
  145. 14 return getTotalResultValueWhenSlash(total, value)
  146. else: 36 else
  147. 36 return translate("DetatokoSaga.total_value", total: total)
  148. end
  149. end
  150. 1 def getTotalResultValueWhenSlash(total, value)
  151. 14 then: 2 else: 12 return translate("DetatokoSaga.division_by_zero_error") if value == 0
  152. 12 quotient = ((1.0 * total) / value).ceil
  153. 12 result = "#{total}÷#{value} > " + translate("DetatokoSaga.total_value", total: quotient)
  154. 12 return result
  155. end
  156. 1 ALIAS = {
  157. "StrengthStigmaTable" => "SST",
  158. "WillStigmaTable" => "WST",
  159. "StrengthBadEndTable" => "SBET",
  160. "WillBadEndTable" => "WBET",
  161. }.transform_keys(&:upcase).freeze
  162. 1 def self.translate_tables(locale)
  163. {
  164. 2 "SST" => DiceTable::Table.from_i18n("DetatokoSaga.table.SST", locale),
  165. "WST" => DiceTable::Table.from_i18n("DetatokoSaga.table.WST", locale),
  166. "SBET" => DiceTable::Table.from_i18n("DetatokoSaga.table.SBET", locale),
  167. "WBET" => DiceTable::Table.from_i18n("DetatokoSaga.table.WBET", locale),
  168. }
  169. end
  170. 1 TABLES = translate_tables(:ja_jp).freeze
  171. 1 register_prefix(TABLES.keys, ALIAS.keys)
  172. end
  173. end
  174. end

lib/bcdice/game_system/DetatokoSaga_Korean.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/DetatokoSaga"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class DetatokoSaga_Korean < DetatokoSaga
  6. # ゲームシステムの識別子
  7. 1 ID = 'DetatokoSaga:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '데타토코 사가'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:데타토코 사가'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・통상판정 xDS or xDSy or xDS>=t or xDSy>=t or xDS+z>=t or xDSy+z>=t
  15.  (x=스킬레벨, y=현재 플래그(생략=0), z=수정치(생략=0), t=목표치(생략=8))
  16.  예)3DS 2DS5 0DS 3DS>=10 3DS7>=12 2DS3+1 3DS2+1>=10
  17. ・판정치 xJD or xJDy or xJDy+z or xJDy-z or xJDy/z
  18.  (x=스킬레벨, y=현재 플래그(생략=0), z=수정치(생략=0))
  19.  예)3JD 2JD5 3JD7+1 4JD/3
  20. ・체력 낙인표 SST (StrengthStigmaTable)
  21. ・기력 낙인표 WST (WillStigmaTable)
  22. ・체력 배드엔딩표 SBET (StrengthBadEndTable)
  23. ・기력 배드엔딩표 WBET (WillBadEndTable)
  24. INFO_MESSAGE_TEXT
  25. 1 register_prefix_from_super_class()
  26. 1 def initialize(command)
  27. 42 super(command)
  28. 42 @locale = :ko_kr
  29. end
  30. 1 TABLES = translate_tables(:ko_kr)
  31. end
  32. end
  33. end

lib/bcdice/game_system/DiceBot.rb

100.0% lines covered

100.0% branches covered

7 relevant lines. 7 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class DiceBot < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'DiceBot'
  7. # ゲームシステム名
  8. 1 NAME = 'DiceBot'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = '*たいすほつと'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~HELP
  13. 3D6+1>=9 :3d6+1で目標値9以上かの判定
  14. 1D100<=50 :D100で50%目標の下方ロールの例
  15. 3U6[5] :3d6のダイス目が5以上の場合に振り足しして合計する(上方無限)
  16. 3B6 :3d6のダイス目をバラバラのまま出力する(合計しない)
  17. 10B6>=4 :10d6を振り4以上のダイス目の個数を数える
  18. 2R6[>3]>=5 :2D6のダイス目が3より大きい場合に振り足して、5以上のダイス目の個数を数える
  19. (8/2)D(4+6)<=(5*3):個数・ダイス・達成値には四則演算も使用可能
  20. c(10-4*3/2+2):c(計算式)で計算だけの実行も可能
  21. choice[a,b,c]:列挙した要素から一つを選択表示。ランダム攻撃対象決定などに
  22. S3d6 : 各コマンドの先頭に「S」を付けると他人結果の見えないシークレットロール
  23. 3d6/2 : ダイス出目を割り算(端数処理はゲームシステム依存)。切り上げは /2C、四捨五入は /2R、切り捨ては /2F
  24. D66 : D66ダイス。順序はゲームに依存。D66N:そのまま、D66A:昇順、D66D:降順
  25. 詳細は下記URLのコマンドガイドを参照
  26. https://docs.bcdice.org/
  27. HELP
  28. end
  29. end
  30. end

lib/bcdice/game_system/DiceOfTheDead.rb

100.0% lines covered

100.0% branches covered

46 relevant lines. 46 lines covered and 0 lines missed.
3 total branches, 3 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class DiceOfTheDead < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'DiceOfTheDead'
  7. # ゲームシステム名
  8. 1 NAME = 'ダイス・オブ・ザ・デッド'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'たいすおふさてつと'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・ゾンビ化表 ZMB+x
  14. (x=オープン中の感染度マスの数。+xは省略可能、省略時は0)
  15. ・感染度表 BIOx
  16. (xは被弾回数。xは省略可能、省略時は1)
  17. (上記二つは最初からシークレットダイスで行われます)
  18. INFO_MESSAGE_TEXT
  19. 1 register_prefix('ZMB', 'BIO')
  20. 1 def initialize(command)
  21. 12 super(command)
  22. 12 @sort_add_dice = true
  23. 12 @d66_sort_type = D66SortType::ASC
  24. end
  25. 1 def eval_game_system_specific_command(command)
  26. 12 else: 1 case command
  27. when: 2 when /^BIO(\d+)?$/
  28. 2 roll_times = (Regexp.last_match(1) || 1).to_i
  29. 2 Result.new.tap do |r|
  30. 2 r.secret = true
  31. 2 r.text = checkInfection(roll_times)
  32. end
  33. when: 9 when /^ZMB(\+(\d+))?$/
  34. 9 value = Regexp.last_match(2).to_i
  35. 9 Result.new.tap do |r|
  36. 9 r.secret = true
  37. 9 r.text = rollZombie(value)
  38. end
  39. end
  40. end
  41. 1 def checkInfection(roll_times)
  42. 2 result = "感染度表"
  43. 2 roll_times.times do
  44. 9 d1 = @randomizer.roll_once(6)
  45. 9 d2 = @randomizer.roll_once(6)
  46. 9 result += " > 出目:#{d1}、#{d2} "
  47. 9 index1 = (d1 / 2.0).ceil - 1
  48. 9 index2 = (d2 / 2.0).ceil - 1
  49. table =
  50. 9 [["「右下(【足】+1)」", "「右中(【足】+1)」", "「右上(【足】+1)」"],
  51. ["「中下(【腕】+1)」", "「真中(【腕】+1)」", "「中上(【腕】+1)」"],
  52. ["「左下(【頭】+1)」", "「左中(【頭】+1)」", "「左上(【頭】+1)」"],]
  53. 9 result += table[index1][index2]
  54. end
  55. 2 return result
  56. end
  57. ####################
  58. # 各種表
  59. 1 def rollZombie(value)
  60. 9 d1 = @randomizer.roll_once(6)
  61. 9 d2 = @randomizer.roll_once(6)
  62. 9 diceTotal = d1 + d2 + value
  63. table = [
  64. 9 [5, "5以下:影響なし"],
  65. [6, "6:任意の部位を1点回復"],
  66. [7, "7:〈アイテム〉武器を1つその場に落とす"],
  67. [8, "8:〈アイテム〉便利道具1つをその場に落とす"],
  68. [9, "9:〈アイテム〉消耗品1つをその場に落とす"],
  69. [10, "10:腕の傷が広がる。「部位:【腕】」1点ダメージ"],
  70. [11, "11:足の傷が広がる。「部位:【足】」1点ダメージ"],
  71. [12, "12:頭の傷が広がる。「部位:【頭】」1点ダメージ"],
  72. [13, "13:【ゾンビ化表】が新たに適用されるまで「【感染度】+1マス」の効果を受ける"],
  73. [14, "14:即座に自分以外の味方1人のスロット内の〈アイテム〉1つをランダムに捨てさせる"],
  74. [15, "15:味方1人に素手で攻撃を行う"],
  75. [16, "16:即座に感染度が1上昇する"],
  76. [17, "17:次のターンのみ、すべての【能力値】を2倍にする"],
  77. [18, "18以上:自分以外の味方1人にできる限り全力で攻撃を行う。〈アイテム〉も可能な限り使用する"]
  78. ]
  79. 9 minDice = table.first.first
  80. 9 maxDice = table.last.first
  81. 9 index = diceTotal
  82. 9 index = [minDice, index].max
  83. 9 index = [index, maxDice].min
  84. 9 _number, text = table.assoc(index)
  85. 9 result = "ゾンビ化表 > 出目:#{d1}+#{d2} 感染度:#{value} 合計値:#{diceTotal} > #{text}"
  86. 9 return result
  87. end
  88. end
  89. end
  90. end

lib/bcdice/game_system/DivineCharger.rb

100.0% lines covered

100.0% branches covered

63 relevant lines. 63 lines covered and 0 lines missed.
12 total branches, 12 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class DivineCharger < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'DivineCharger'
  7. # ゲームシステム名
  8. 1 NAME = '神聖課金RPGディヴァインチャージャー'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'しんせいかきんRPGていうあいんちやあしやあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGETEXT
  13. ■判定  nDC>=t n:能力値 t:目標値
  14. 例)3DC>=7: ダイスを3個振って、目標値7で判定。その結果(達成値,成功・失敗,クリティカル,ファンブル)を表示
  15.   3DC>=?:  同上 目標値が不明なので、達成値,クリティカル,ファンブルのみ表示。
  16. ■反転判定  REV[n]>=t n:ダイス目(カンマなし) t:目標値
  17. 例)REV[123]>=7: 振ったダイスが[1,2,3]で、目標値7で反転判定。その結果(達成値,成功・失敗,クリティカル,ファンブル)を表示
  18. ■ランダムイベント  RET
  19. ■神器        aksT a:表(AかB) k:種別(K:近接, S:射撃, M:魔法, Y:鎧, T:盾, A:装飾品) s:ランク(1~5)
  20. INFO_MESSAGETEXT
  21. 1 def initialize(command)
  22. 71 super(command)
  23. 71 @sort_barabara_dice = true # バラバラロール(Bコマンド)でソート有
  24. 71 @d66_sort_type = D66SortType::NO_SORT
  25. end
  26. 1 def eval_game_system_specific_command(command)
  27. 71 resolute_action(command) ||
  28. resolute_reverse(command) ||
  29. roll_tables(command, TABLES)
  30. end
  31. 1 private
  32. # 通常判定
  33. # @param [String] command
  34. # @return [Result]
  35. 1 def resolute_action(command)
  36. 71 m = /^(\d+)DC>=(\d+|\?)$/.match(command)
  37. 71 else: 6 then: 65 return nil unless m
  38. 6 num_dice = m[1].to_i
  39. 6 target = m[2]
  40. 6 dice = @randomizer.roll_barabara(num_dice, 6).sort
  41. 6 dice_text = dice.join(",")
  42. 6 output = "(#{num_dice}DC>=#{target}) > #{dice_text}"
  43. 6 action = Action_data.new(output, dice, target)
  44. 6 return action_result(action)
  45. end
  46. 1 Action_data = Struct.new(:text, :dice, :target)
  47. 1 def action_result(action)
  48. 7 output = action.text
  49. 7 dice = action.dice
  50. 7 target = action.target
  51. 7 count6 = dice.count(6)
  52. 7 count1 = dice.count(1)
  53. 7 success_num = dice.sum()
  54. 7 then: 2 if count6 >= 2
  55. 2 output += " > 達成値#{success_num}"
  56. 2 output += " > クリティカル"
  57. 2 else: 5 return Result.critical(output)
  58. 5 then: 1 else: 4 elsif count1 >= 2
  59. 1 output += " > 達成値0"
  60. 1 output += " > ファンブル([神聖石]5個)"
  61. 1 return Result.fumble(output)
  62. end
  63. 4 output += " > 達成値#{success_num}"
  64. 4 then: 1 if target == "?"
  65. 1 return Result.new(output)
  66. else: 3 else
  67. 3 then: 2 if success_num >= target.to_i
  68. 2 output += " > 成功"
  69. 2 return Result.success(output)
  70. else: 1 else
  71. 1 output += " > 失敗"
  72. 1 return Result.failure(output)
  73. end
  74. end
  75. end
  76. # 反転判定
  77. # @param [String] command
  78. # @return [Result]
  79. 1 def resolute_reverse(command)
  80. 65 m = /^REV\[([\d,]+)\]>=(\d+|\?)$/.match(command)
  81. 65 else: 1 then: 64 return nil unless m
  82. 1 raw_dice = m[1]
  83. 1 target = m[2]
  84. 1 raw_dice = raw_dice.delete(',')
  85. 1 dice = reverse_dice(raw_dice.split(''))
  86. 1 dice_text = dice.join(",")
  87. 1 output = "(REV[#{raw_dice}]>=#{target}) > #{dice_text}"
  88. 1 action = Action_data.new(output, dice, target)
  89. 1 return action_result(action)
  90. end
  91. 1 def reverse_dice(array_dice)
  92. # 出目を 1 <-> 6, 2 <-> 5, 3 <-> 4 で反転させる
  93. 7 array_dice.map(&:to_i).filter { |v| 1 <= v && v <= 6 }.map { |v| 7 - v.to_i }.sort
  94. end
  95. TABLES = {
  96. 1 "RET" => DiceTable::D66Table.new(
  97. "ランダムイベント",
  98. D66SortType::NO_SORT,
  99. {
  100. 11 => '[描写]:辺りには何もなく、がらんとした部屋だ。近くに宝箱がある。[予測]:こういう場所では運動神経を試される罠が仕掛けてあることが多い。宝箱の中には、当然ながら金目のものが眠っているはずだ。[探索時間:4]',
  101. 12 => '[描写]:辺りには何もなく、がらんとした部屋だ。近くに宝箱がある。[予測]:こういう場所では運動神経を試される罠が仕掛けてあることが多い。宝箱の中には、当然ながら金目のものが眠っているはずだ。[探索時間:4]',
  102. 13 => '[描写]:辺りには何もなく、がらんとした部屋だ。向こう側に宝箱がある。[予測]:悪い予感がする。妙なトラップに遭遇するかもしれない。心の準備をしておいた方がいいだろう。宝箱には何かアイテムがあるような気がする。[探索時間:4]',
  103. 14 => '[描写]:辺りには何もなく、がらんとした部屋だ。向こう側に宝箱がある。[予測]:悪い予感がする。妙なトラップに遭遇するかもしれない。心の準備をしておいた方がいいだろう。宝箱には何かアイテムがあるような気がする。[探索時間:4]',
  104. 15 => '[描写]:辺りには何もなく、がらんとした部屋だ。中央に宝箱がある。[予測]:一見何もないように見える場所こそ注意が必要だ。いつでも立ち回れるようにした方がいいだろう。宝箱の中から光がにじみ出している。まさか〈神聖石〉が入っているのでは。[探索時間:4]',
  105. 16 => '[描写]:辺りには何もなく、がらんとした部屋だ。中央に宝箱がある。[予測]:一見何もないように見える場所こそ注意が必要だ。いつでも立ち回れるようにした方がいいだろう。宝箱の中から光がにじみ出している。まさか〈神聖石〉が入っているのでは。[探索時間:4]',
  106. 21 => '[描写]:石の壁で覆われた部屋だ。壁には幾何学的な模様が彫ってある。天井も無数の石のブロックで形成されている。[予測]:天井が崩れそうな予感がする。素早く探索しないと怪我しそうだ。ここには〈神聖石〉がある気がする。[探索時間:5]',
  107. 22 => '[描写]:石の壁で覆われた部屋だ。壁には幾何学的な模様が彫ってある。天井も無数の石のブロックで形成されている。[予測]:天井が崩れそうな予感がする。素早く探索しないと怪我しそうだ。ここには〈神聖石〉がある気がする。[探索時間:5]',
  108. 23 => '[描写]:石の壁で覆われた部屋だ。壁には様々なe壁画が彫ってある。[予測]:何か違和感がある。己の感覚を研ぎ澄まし注意した方がいいだろう。部屋の中央には宝箱が置いてある。[探索時間:5]',
  109. 24 => '[描写]:石の壁で覆われた部屋だ。壁には様々なe壁画が彫ってある。[予測]:何か違和感がある。己の感覚を研ぎ澄まし注意した方がいいだろう。部屋の中央には宝箱が置いてある。[探索時間:5]',
  110. 25 => '[描写]:石の壁で覆われた部屋だ。壁は光苔に覆われて輝いている。探せば何かあるかもしれない。[予測]:何か違和感を覚える。この違和感を押さえ込まないと、今後の行動に支障が出てきそうだ。部屋の端には薬棚があり、魔法薬が置いてある。[探索時間:5]',
  111. 26 => '[描写]:石の壁で覆われた部屋だ。壁は光苔に覆われて輝いている。探せば何かあるかもしれない。[予測]:何か違和感を覚える。この違和感を押さえ込まないと、今後の行動に支障が出てきそうだ。部屋の端には薬棚があり、魔法薬が置いてある。[探索時間:5]',
  112. 31 => '[描写]:小さな部屋だ。雑多に物がちらかっている。ガラクタから、何かを見つけることができるかもしれない。[予測]:こういうところでこそ、油断してはいけない。隙を突くようなトラップが仕掛けている場合がある。俊敏に動こう。ガラクタの中には、魔法薬の瓶がある。[探索時間:4]',
  113. 32 => '[描写]:小さな部屋だ。雑多に物がちらかっている。ガラクタから、何かを見つけることができるかもしれない。[予測]:こういうところでこそ、油断してはいけない。隙を突くようなトラップが仕掛けている場合がある。俊敏に動こう。ガラクタの中には、魔法薬の瓶がある。[探索時間:4]',
  114. 33 => '[描写]:小さな部屋だ。雑多に物がちらかっている。ガラクタの中から、何かいいものが落ちているかもしれない。[予測]:こういう場所には大体トラップが置いてあるはずだが、今のところその気配はない。感覚を研ぎ澄ませて慎重に行こう。隅に光る石がある。〈神聖石〉だろうか。[探索時間:3]',
  115. 34 => '[描写]:小さな部屋だ。雑多に物がちらかっている。ガラクタの中から、何かいいものが落ちているかもしれない。[予測]:こういう場所には大体トラップが置いてあるはずだが、今のところその気配はない。感覚を研ぎ澄ませて慎重に行こう。隅に光る石がある。〈神聖石〉だろうか。[探索時間:3]',
  116. 35 => '[描写]:小さな部屋だ。雑多に物がちらかっている。隅には宝箱が見える。[予測]:何やらすえた匂いがする。酸を使ったトラップがあるかもしれない。機敏に動こう。宝箱には金目の物があるだろう。[探索時間:3]',
  117. 36 => '[描写]:小さな部屋だ。雑多に物がちらかっている。隅には宝箱が見える。[予測]:何やらすえた匂いがする。酸を使ったトラップがあるかもしれない。機敏に動こう。宝箱には金目の物があるだろう。[探索時間:3]',
  118. 41 => '[描写]:光が差し込みにくい、薄暗い部屋だ。伸ばした自分の手の先もよく見えない。[予測]:このような場所ではうかつに動くと怪我をしてしまう。感覚を研ぎ澄まして動いた方がいいだろう。ここには〈神聖石〉がある気がする。[探索時間:4]',
  119. 42 => '[描写]:光が差し込みにくい、薄暗い部屋だ。伸ばした自分の手の先もよく見えない。[予測]:このような場所ではうかつに動くと怪我をしてしまう。感覚を研ぎ澄まして動いた方がいいだろう。ここには〈神聖石〉がある気がする。[探索時間:4]',
  120. 43 => '[描写]:光が差し込みにくい暗い部屋だ。探索には骨が折れるかもしれない。[予測]:このような場所では何が起きるかわからない。何が起きても動じない心構えが必要だ。身につけてるものもちゃんと管理しておこう。ここには宝がある気がする。[探索時間:4]',
  121. 44 => '[描写]:光が差し込みにくい暗い部屋だ。探索には骨が折れるかもしれない。[予測]:このような場所では何が起きるかわからない。何が起きても動じない心構えが必要だ。身につけてるものもちゃんと管理しておこう。ここには宝がある気がする。[探索時間:4]',
  122. 45 => '[描写]:光が差し込みにくい薄暗い部屋だ。何やら生き物の気配も感じる。[予測]:どんな生物がいるのか、探っておく必要があるだろう。対処方法につながる。ここには霊薬が置いてある気がする。[探索時間:4]',
  123. 46 => '[描写]:光が差し込みにくい薄暗い部屋だ。何やら生き物の気配も感じる。[予測]:どんな生物がいるのか、探っておく必要があるだろう。対処方法につながる。ここには霊薬が置いてある気がする。[探索時間:4]',
  124. 51 => '[描写]:床や天井におどろおどろしい魔法陣が描かれている部屋だ。四方の壁には棚が置かれている。何か見つかればいいのだが。[予測]:魔法陣は明らかに怪しい。いつでも対応できるよう感覚を研ぎ澄ませ、装備にも気を配っておこう。棚には魔法の薬が置いてあるようだ。[探索時間:4]',
  125. 52 => '[描写]:床や天井におどろおどろしい魔法陣が描かれている部屋だ。四方の壁には棚が置かれている。何か見つかればいいのだが。[予測]:魔法陣は明らかに怪しい。いつでも対応できるよう感覚を研ぎ澄ませ、装備にも気を配っておこう。棚には魔法の薬が置いてあるようだ。[探索時間:4]',
  126. 53 => '[描写]:床や天井におどろおどろしい魔法陣が描かれている部屋だ。探索すれば何かあるかもしれない。[予測]:魔法陣は明らかに怪しい。これに罠があるとするなら、知性を試されるようなものに違いない。注意しておこう。この部屋には〈神聖石〉がある気がする。[探索時間:4]',
  127. 54 => '[描写]:床や天井におどろおどろしい魔法陣が描かれている部屋だ。探索すれば何かあるかもしれない。[予測]:魔法陣は明らかに怪しい。これに罠があるとするなら、知性を試されるようなものに違いない。注意しておこう。この部屋には〈神聖石〉がある気がする。[探索時間:4]',
  128. 55 => '[描写]:床や天井におどろおどろしい魔法陣が描かれている部屋だ。探索すれば何かあるかもしれない。[予測]:この魔法陣が罠であるのは間違いない。いつでも対応できるように俊敏に行動しよう。部屋の隅には宝箱があり、金目の物が入ってそうだ。[探索時間:4]',
  129. 56 => '[描写]:床や天井におどろおどろしい魔法陣が描かれている部屋だ。探索すれば何かあるかもしれない。[予測]:この魔法陣が罠であるのは間違いない。いつでも対応できるように俊敏に行動しよう。部屋の隅には宝箱があり、金目の物が入ってそうだ。[探索時間:4]',
  130. 61 => '[描写]:静謐な部屋だ。中央には泉があり、清らかな空気を放っている。泉のそばにはキノコが生えている。慎重に食べた方がいいだろう。[予測]:キノコは魔法のキノコで、何かしらの効果が期待されるが、キノコの魔法成分を受け止める精神力が必要だ。また、泉の中には金貨が見える。[探索時間:3]',
  131. 62 => '[描写]:静謐な部屋だ。中央には泉があり、清らかな空気を放っている。泉のそばにはキノコが生えている。慎重に食べた方がいいだろう。[予測]:キノコは魔法のキノコで、何かしらの効果が期待されるが、キノコの魔法成分を受け止める精神力が必要だ。また、泉の中には金貨が見える。[探索時間:3]',
  132. 63 => '[描写]:神聖な雰囲気の漂う部屋だ。中央には泉があり、清らかな空気を放っている。とりあえず飲んでみるべきだろう。[予測]:泉の水には何らかの効果が期待できそうだが、もしもの時のために体力があった方がいいだろう。また、泉の中には〈神聖石〉が見える。[探索時間:3]',
  133. 64 => '[描写]:神聖な雰囲気の漂う部屋だ。中央には泉があり、清らかな空気を放っている。とりあえず飲んでみるべきだろう。[予測]:泉の水には何らかの効果が期待できそうだが、もしもの時のために体力があった方がいいだろう。また、泉の中には〈神聖石〉が見える。[探索時間:3]',
  134. 65 => '[描写]:静謐な部屋だ。中央には泉があり、清らかな空気を放っている。泉の中には何かあるかも知れない。[予測]:泉の中には何かが潜んでいるかもしれない。俊敏に対応できるように注意するべきだろう。また、泉の中には薬瓶が見える。[探索時間:3]',
  135. 66 => '[描写]:静謐な部屋だ。中央には泉があり、清らかな空気を放っている。泉の中には何かあるかも知れない。[予測]:泉の中には何かが潜んでいるかもしれない。俊敏に対応できるように注意するべきだろう。また、泉の中には薬瓶が見える。[探索時間:3]',
  136. }
  137. ),
  138. "AK1T" => DiceTable::Table.new(
  139. "[神器:近接]表A☆1",
  140. "1D6",
  141. [
  142. 'フレイムソード P.82',
  143. 'サンダースピア P.82',
  144. 'ディフェンダー P.82',
  145. 'ビッグロック P.82',
  146. 'ブラックジャック P.82',
  147. 'ランクアップ?([神聖石]10個)',
  148. ]
  149. ),
  150. "AK2T" => DiceTable::Table.new(
  151. "[神器:近接]表A☆2",
  152. "1D6",
  153. [
  154. 'イチモンジブレード P.82',
  155. 'レオソード P.82',
  156. 'ブラッドアックス P.82',
  157. 'ウッドバスター P.82',
  158. 'クラブライブ P.82',
  159. 'ランクアップ?([神聖石]20個)',
  160. ]
  161. ),
  162. "AK3T" => DiceTable::Table.new(
  163. "[神器:近接]表A☆3",
  164. "1D6",
  165. [
  166. 'ソニックブレード P.83',
  167. 'アブソリュートゼロ P.83',
  168. 'ブライトアックス P.83',
  169. 'ブレスメイス P.83',
  170. 'レッドソード P.83',
  171. 'ランクアップ?([神聖石]30個)',
  172. ]
  173. ),
  174. "AK4T" => DiceTable::Table.new(
  175. "[神器:近接]表A☆4",
  176. "1D6",
  177. [
  178. 'ディヴァインブレード P.83',
  179. 'ゴリラソード P.83',
  180. 'ジャホコ P.83',
  181. 'ゴローマサムネ P.83',
  182. 'ドンキードンキ P.83',
  183. 'ランクアップ?([神聖石]40個)',
  184. ]
  185. ),
  186. "AK5T" => DiceTable::Table.new(
  187. "[神器:近接]表A☆5",
  188. "1D1",
  189. [
  190. 'カタストロフ P.83',
  191. ]
  192. ),
  193. "AS1T" => DiceTable::Table.new(
  194. "[神器:射撃]表A☆1",
  195. "1D6",
  196. [
  197. 'ライトボウ P.84',
  198. 'ウィンドブレイカー P.84',
  199. 'マシンクロスボウ P.84',
  200. 'マッハボウ P.84',
  201. 'シャープチャクラム P.84',
  202. 'ランクアップ?([神聖石]10個)',
  203. ]
  204. ),
  205. "AS2T" => DiceTable::Table.new(
  206. "[神器:射撃]表A☆2",
  207. "1D6",
  208. [
  209. 'ラストシューター P.84',
  210. 'マグネットボウ P.84',
  211. 'ビッグブーメラン P.84',
  212. 'ホーミングシューター P.84',
  213. 'アサシンチャクラム P.84',
  214. 'ランクアップ?([神聖石]20個)',
  215. ]
  216. ),
  217. "AS3T" => DiceTable::Table.new(
  218. "[神器:射撃]表A☆3",
  219. "1D6",
  220. [
  221. 'パワーライフル P.85',
  222. 'フレイムガン P.85',
  223. 'エレクトロスター P.85',
  224. 'ナパームシューター P.85',
  225. 'ラインヒーラー P.85',
  226. 'ランクアップ?([神聖石]30個)',
  227. ]
  228. ),
  229. "AS4T" => DiceTable::Table.new(
  230. "[神器:射撃]表A☆4",
  231. "1D6",
  232. [
  233. 'ストーカーボウ P.85',
  234. 'ビームチャクラム P.85',
  235. 'アストラルボウ P.85',
  236. 'フォーチュンガン P.85',
  237. 'ウォークライボウ P.85',
  238. 'ランクアップ?([神聖石]40個)',
  239. ]
  240. ),
  241. "AS5T" => DiceTable::Table.new(
  242. "[神器:射撃]表A☆5",
  243. "1D1",
  244. [
  245. 'オートリピーター P.85',
  246. ]
  247. ),
  248. "AM1T" => DiceTable::Table.new(
  249. "[神器:魔法]表A☆1",
  250. "1D6",
  251. [
  252. 'スカーレットワンド P.86',
  253. 'クラウドスタッフ P.86',
  254. 'アイスジュエル P.86',
  255. 'パワーワンド P.86',
  256. 'ジーニアスブック P.86',
  257. 'ランクアップ?([神聖石]10個)',
  258. ]
  259. ),
  260. "AM2T" => DiceTable::Table.new(
  261. "[神器:魔法]表A☆2",
  262. "1D6",
  263. [
  264. 'ヘルアポカリプス P.86',
  265. 'シャーマニックスカル P.86',
  266. 'カーズタスク P.86',
  267. 'バリアロッド P.86',
  268. 'ホーリーベル P.86',
  269. 'ランクアップ?([神聖石]20個)',
  270. ]
  271. ),
  272. "AM3T" => DiceTable::Table.new(
  273. "[神器:魔法]表A☆3",
  274. "1D6",
  275. [
  276. 'オーシャンワンド P.87',
  277. 'ダーククラウド P.87',
  278. 'ワイズマン P.87',
  279. 'エンシェントワンド P.87',
  280. 'ゴッドゴブレット P.87',
  281. 'ランクアップ?([神聖石]30個)',
  282. ]
  283. ),
  284. "AM4T" => DiceTable::Table.new(
  285. "[神器:魔法]表A☆4",
  286. "1D6",
  287. [
  288. 'テンペストロッド P.87',
  289. 'セイバースタッフ P.87',
  290. 'ダークスカッター P.87',
  291. 'ルーラーズレイ P.87',
  292. 'デモンズホーン P.87',
  293. 'ランクアップ?([神聖石]40個)',
  294. ]
  295. ),
  296. "AM5T" => DiceTable::Table.new(
  297. "[神器:魔法]表A☆5",
  298. "1D1",
  299. [
  300. 'スターコンプレッサ P.87',
  301. ]
  302. ),
  303. "AY1T" => DiceTable::Table.new(
  304. "[神器:鎧]表A☆1",
  305. "1D6",
  306. [
  307. 'ハードアーマー P.88',
  308. 'シーヴスローブ P.88',
  309. 'マジックアーマー P.88',
  310. 'ナイトアーマー P.88',
  311. 'フェザーキルト P.88',
  312. 'ランクアップ?([神聖石]10個)',
  313. ]
  314. ),
  315. "AY2T" => DiceTable::Table.new(
  316. "[神器:鎧]表A☆2",
  317. "1D6",
  318. [
  319. 'トワイライトアーマー P.88',
  320. 'ヒューマンガーター P.88',
  321. 'ソルトメイル P.88',
  322. 'ライトムーヴ P.88',
  323. 'キャプテンアーマー P.88',
  324. 'ランクアップ?([神聖石]20個)',
  325. ]
  326. ),
  327. "AY3T" => DiceTable::Table.new(
  328. "[神器:鎧]表A☆3",
  329. "1D6",
  330. [
  331. 'ジェットアーマー P.89',
  332. 'ドラゴンアーマー P.89',
  333. 'ホーリーケープ P.89',
  334. 'ビーストエイジ P.89',
  335. 'クロスフォートレス P.89',
  336. 'ランクアップ?([神聖石]30個)',
  337. ]
  338. ),
  339. "AY4T" => DiceTable::Table.new(
  340. "[神器:鎧]表A☆4",
  341. "1D6",
  342. [
  343. 'フェニックスアーマー P.89',
  344. 'マジックゲイナー P.89',
  345. 'インシュランスメイル P.89',
  346. 'ジャイアントメイル P.89',
  347. 'バンブーメイル P.89',
  348. 'ランクアップ?([神聖石]40個)',
  349. ]
  350. ),
  351. "AY5T" => DiceTable::Table.new(
  352. "[神器:鎧]表A☆5",
  353. "1D1",
  354. [
  355. 'ディヴァインクロス P.89',
  356. ]
  357. ),
  358. "AT1T" => DiceTable::Table.new(
  359. "[神器:盾]表A☆1",
  360. "1D6",
  361. [
  362. 'スパイクシールド P.90',
  363. 'ウェーブシールド P.90',
  364. 'レアメタルシールド P.90',
  365. 'バインドシールド P.90',
  366. 'ゲイルシールド P.90',
  367. 'ランクアップ?([神聖石]10個)',
  368. ]
  369. ),
  370. "AT2T" => DiceTable::Table.new(
  371. "[神器:盾]表A☆2",
  372. "1D6",
  373. [
  374. 'アースシールド P.90',
  375. 'フレイムレジスター P.90',
  376. 'ポラリゼーショナー P.90',
  377. 'グレートシールド P.90',
  378. 'センサーシールド P.90',
  379. 'ランクアップ?([神聖石]20個)',
  380. ]
  381. ),
  382. "AT3T" => DiceTable::Table.new(
  383. "[神器:盾]表A☆3",
  384. "1D6",
  385. [
  386. 'ヒールボード P.91',
  387. 'フレッシュガーダー P.91',
  388. 'タフシールド P.91',
  389. 'ワイズモノリス P.91',
  390. 'エールポンポン P.91',
  391. 'ランクアップ?([神聖石]30個)',
  392. ]
  393. ),
  394. "AT4T" => DiceTable::Table.new(
  395. "[神器:盾]表A☆4",
  396. "1D6",
  397. [
  398. 'ガッデスミラー P.91',
  399. 'ラックエムブレム P.91',
  400. 'バトルドレイナー P.91',
  401. 'グランドソーサー P.91',
  402. 'オートドール P.91',
  403. 'ランクアップ?([神聖石]40個)',
  404. ]
  405. ),
  406. "AT5T" => DiceTable::Table.new(
  407. "[神器:盾]表A☆5",
  408. "1D1",
  409. [
  410. 'ダークマター P.91',
  411. ]
  412. ),
  413. "AA1T" => DiceTable::Table.new(
  414. "[神器:装飾品]表A☆1",
  415. "1D6",
  416. [
  417. 'エナジーブレス P.92',
  418. 'ホークガントレット P.92',
  419. 'ライトアミュレット P.92',
  420. 'センシングブレス P.92',
  421. 'レジストマント P.92',
  422. 'ランクアップ?([神聖石]10個)',
  423. ]
  424. ),
  425. "AA2T" => DiceTable::Table.new(
  426. "[神器:装飾品]表A☆2",
  427. "1D6",
  428. [
  429. 'ドリルブレス P.92',
  430. 'ルーンマント P.92',
  431. 'バランスビット P.92',
  432. 'ベストサングラス P.92',
  433. 'シルバーペンダント P.92',
  434. 'ランクアップ?([神聖石]20個)',
  435. ]
  436. ),
  437. "AA3T" => DiceTable::Table.new(
  438. "[神器:装飾品]表A☆3",
  439. "1D6",
  440. [
  441. 'ミスティックマスク P.93',
  442. 'ガードブレス P.93',
  443. 'マジックピアス P.93',
  444. 'ミラージュブレス P.93',
  445. 'キャットフード P.93',
  446. 'ランクアップ?([神聖石]30個)',
  447. ]
  448. ),
  449. "AA4T" => DiceTable::Table.new(
  450. "[神器:装飾品]表A☆4",
  451. "1D6",
  452. [
  453. 'ショルダーアーム P.93',
  454. 'ナイトコート P.93',
  455. 'エンジェルバックル P.93',
  456. 'オラクルピアス P.93',
  457. 'センサーリング P.93',
  458. 'ランクアップ?([神聖石]40個)',
  459. ]
  460. ),
  461. "AA5T" => DiceTable::Table.new(
  462. "[神器:装飾品]表A☆5",
  463. "1D1",
  464. [
  465. 'ノーブルスフィア P.93',
  466. ]
  467. ),
  468. "BK1T" => DiceTable::Table.new(
  469. "[神器:近接]表B☆1",
  470. "1D6",
  471. [
  472. 'マンイーター P.94',
  473. 'アイスメイス P.94',
  474. 'エクステンダー P.94',
  475. 'スラッグカッター P.94',
  476. 'フィアーギロチン P.94',
  477. 'ランクアップ?([神聖石]10個)',
  478. ]
  479. ),
  480. "BK2T" => DiceTable::Table.new(
  481. "[神器:近接]表B☆2",
  482. "1D6",
  483. [
  484. 'ツインランサー P.94',
  485. 'メディシンランス P.94',
  486. 'レイスラッシャー P.94',
  487. 'シザーソード P.94',
  488. 'エナジーヨーヨー P.94',
  489. 'ランクアップ?([神聖石]20個)',
  490. ]
  491. ),
  492. "BK3T" => DiceTable::Table.new(
  493. "[神器:近接]表B☆3",
  494. "1D6",
  495. [
  496. 'ラディオランサー P.95',
  497. 'マシンキラー P.95',
  498. 'ニンジャハンマー P.95',
  499. 'ストームブレード P.95',
  500. 'オートバランサー P.95',
  501. 'ランクアップ?([神聖石]30個)',
  502. ]
  503. ),
  504. "BK4T" => DiceTable::Table.new(
  505. "[神器:近接]表B☆4",
  506. "1D6",
  507. [
  508. 'ラムダセイバー P.95',
  509. 'エクスカリアックス P.95',
  510. 'ゴッドロック P.95',
  511. 'バスターメイス P.95',
  512. 'グルメランサー P.95',
  513. 'ランクアップ?([神聖石]40個)',
  514. ]
  515. ),
  516. "BK5T" => DiceTable::Table.new(
  517. "[神器:近接]表B☆5",
  518. "1D1",
  519. [
  520. 'カタストロフ P.95',
  521. ]
  522. ),
  523. "BS1T" => DiceTable::Table.new(
  524. "[神器:射撃]表B☆1",
  525. "1D6",
  526. [
  527. 'ホーリースリング P.96',
  528. 'ハンターボウ P.96',
  529. 'ミラージュダーツ P.96',
  530. 'ベストダーツ P.96',
  531. 'エイミングボウ P.96',
  532. 'ランクアップ?([神聖石]10個)',
  533. ]
  534. ),
  535. "BS2T" => DiceTable::Table.new(
  536. "[神器:射撃]表B☆2",
  537. "1D6",
  538. [
  539. 'ラビットボウ P.96',
  540. 'スティングダーツ P.96',
  541. 'ビジネスカード P.96',
  542. 'エクスプロードボウ P.96',
  543. 'インパクトエアガン P.96',
  544. 'ランクアップ?([神聖石]20個)',
  545. ]
  546. ),
  547. "BS3T" => DiceTable::Table.new(
  548. "[神器:射撃]表B☆3",
  549. "1D6",
  550. [
  551. 'オーガシューター P.97',
  552. 'マーダーボウガン P.97',
  553. 'メンタルドレイナー P.97',
  554. 'スタナーガン P.97',
  555. 'ニードルシューター P.97',
  556. 'ランクアップ?([神聖石]30個)',
  557. ]
  558. ),
  559. "BS4T" => DiceTable::Table.new(
  560. "[神器:射撃]表B☆4",
  561. "1D6",
  562. [
  563. 'ガーディアンボウ P.97',
  564. 'フォトンブーメラン P.97',
  565. 'ダンスマシンガン P.97',
  566. 'スリリングスリング P.97',
  567. 'アルケミストガン P.97',
  568. 'ランクアップ?([神聖石]40個)',
  569. ]
  570. ),
  571. "BS5T" => DiceTable::Table.new(
  572. "[神器:射撃]表B☆5",
  573. "1D1",
  574. [
  575. 'オートリピーター P.97',
  576. ]
  577. ),
  578. "BM1T" => DiceTable::Table.new(
  579. "[神器:魔法]表B☆1",
  580. "1D6",
  581. [
  582. 'ソニックスタッフ P.98',
  583. 'ホーリーワンド P.98',
  584. 'ライフメイカー P.98',
  585. 'ゴリラワンド P.98',
  586. 'コンセントレイター P.98',
  587. 'ランクアップ?([神聖石]10個)',
  588. ]
  589. ),
  590. "BM2T" => DiceTable::Table.new(
  591. "[神器:魔法]表B☆2",
  592. "1D6",
  593. [
  594. 'ポイズンワンド P.98',
  595. 'キーンタロー P.98',
  596. 'マジックビースト P.98',
  597. 'オープニングスタッフ P.98',
  598. 'ディヴァイドジュエル P.98',
  599. 'ランクアップ?([神聖石]20個)',
  600. ]
  601. ),
  602. "BM3T" => DiceTable::Table.new(
  603. "[神器:魔法]表B☆3",
  604. "1D6",
  605. [
  606. 'サイクロンアイ P.99',
  607. 'クリムゾンオーブ P.99',
  608. 'ルーインスタッフ P.99',
  609. 'アジリティオーブ P.99',
  610. 'キングステッキ P.99',
  611. 'ランクアップ?([神聖石]30個)',
  612. ]
  613. ),
  614. "BM4T" => DiceTable::Table.new(
  615. "[神器:魔法]表B☆4",
  616. "1D6",
  617. [
  618. 'ディヴァインドラム P.99',
  619. 'エンリッチオーブ P.99',
  620. 'ヒールアミュレット P.99',
  621. 'マナインヘイラー P.99',
  622. 'ライトライト P.99',
  623. 'ランクアップ?([神聖石]40個)',
  624. ]
  625. ),
  626. "BM5T" => DiceTable::Table.new(
  627. "[神器:魔法]表B☆5",
  628. "1D1",
  629. [
  630. 'スターコンプレッサ P.99',
  631. ]
  632. ),
  633. "BY1T" => DiceTable::Table.new(
  634. "[神器:鎧]表B☆1",
  635. "1D6",
  636. [
  637. 'ダンボールボックス P.100',
  638. 'マーチャントクロス P.100',
  639. 'ウィザードローブ P.100',
  640. 'バランスアーマー P.100',
  641. 'レジストローブ P.100',
  642. 'ランクアップ?([神聖石]10個)',
  643. ]
  644. ),
  645. "BY2T" => DiceTable::Table.new(
  646. "[神器:鎧]表B☆2",
  647. "1D6",
  648. [
  649. 'スカウトローブ P.100',
  650. 'ランプアーマー P.100',
  651. 'フィールドローブ P.100',
  652. 'ケミカルアーマー P.100',
  653. 'ビジネススーツ P.100',
  654. 'ランクアップ?([神聖石]20個)',
  655. ]
  656. ),
  657. "BY3T" => DiceTable::Table.new(
  658. "[神器:鎧]表B☆3",
  659. "1D6",
  660. [
  661. 'セージアーマー P.101',
  662. 'トータスアーマー P.101',
  663. 'ブレスブレスト P.101',
  664. 'ラビットスーツ P.101',
  665. 'サクリファイスメイル P.101',
  666. 'ランクアップ?([神聖石]30個)',
  667. ]
  668. ),
  669. "BY4T" => DiceTable::Table.new(
  670. "[神器:鎧]表B☆4",
  671. "1D6",
  672. [
  673. 'ファルコンアーマー P.101',
  674. 'ガッツアーマー P.101',
  675. 'ゴットカーボン P.101',
  676. 'パワードアーマー P.101',
  677. 'グラビティガード P.101',
  678. 'ランクアップ?([神聖石]40個)',
  679. ]
  680. ),
  681. "BY5T" => DiceTable::Table.new(
  682. "[神器:鎧]表B☆5",
  683. "1D1",
  684. [
  685. 'ディヴァインクロス P.101',
  686. ]
  687. ),
  688. "BT1T" => DiceTable::Table.new(
  689. "[神器:盾]表B☆1",
  690. "1D6",
  691. [
  692. 'ルーンボード P.102',
  693. 'ラブリーペット P.102',
  694. 'ハリケーンシールド P.102',
  695. 'ジュークシールド P.102',
  696. 'ミラーシールド P.102',
  697. 'ランクアップ?([神聖石]10個)',
  698. ]
  699. ),
  700. "BT2T" => DiceTable::Table.new(
  701. "[神器:盾]表B☆2",
  702. "1D6",
  703. [
  704. 'フリーズカウンター P.102',
  705. 'ゲイルガーダー P.102',
  706. 'フォースバックラー P.102',
  707. 'ロードシールド P.102',
  708. 'ビッグドーナツ P.102',
  709. 'ランクアップ?([神聖石]20個)',
  710. ]
  711. ),
  712. "BT3T" => DiceTable::Table.new(
  713. "[神器:盾]表B☆3",
  714. "1D6",
  715. [
  716. 'ナイスボード P.103',
  717. 'シニスターシールド P.103',
  718. 'ノーブルソーサー P.103',
  719. 'ミサイルシールド P.103',
  720. 'ゴリラシールド P.103',
  721. 'ランクアップ?([神聖石]30個)',
  722. ]
  723. ),
  724. "BT4T" => DiceTable::Table.new(
  725. "[神器:盾]表B☆4",
  726. "1D6",
  727. [
  728. 'ビームバックラー P.103',
  729. 'オールドシールド P.103',
  730. 'サニーガード P.103',
  731. 'ゴッドクロック P.103',
  732. 'ミストシールド P.103',
  733. 'ランクアップ?([神聖石]40個)',
  734. ]
  735. ),
  736. "BT5T" => DiceTable::Table.new(
  737. "[神器:盾]表B☆5",
  738. "1D1",
  739. [
  740. 'ダークマター P.103',
  741. ]
  742. ),
  743. "BA1T" => DiceTable::Table.new(
  744. "[神器:装飾品]表B☆1",
  745. "1D6",
  746. [
  747. 'ラックデビルアイ P.104',
  748. 'ビームリング P.104',
  749. 'ダッシューズ P.104',
  750. 'エレガンダイ P.104',
  751. 'スキルブック P.104',
  752. 'ランクアップ?([神聖石]10個)',
  753. ]
  754. ),
  755. "BA2T" => DiceTable::Table.new(
  756. "[神器:装飾品]表B☆2",
  757. "1D6",
  758. [
  759. 'ブレスアイドル P.104',
  760. 'アロマピアス P.104',
  761. 'スピードリング P.104',
  762. 'ハイホーリーシンボル P.104',
  763. 'ノーブルマント P.104',
  764. 'ランクアップ?([神聖石]20個)',
  765. ]
  766. ),
  767. "BA3T" => DiceTable::Table.new(
  768. "[神器:装飾品]表B☆3",
  769. "1D6",
  770. [
  771. 'シュルダーバード P.105',
  772. 'フェアリードール P.105',
  773. 'フレッシュブレス P.105',
  774. 'ラビットフット P.105',
  775. 'ファストブレス P.105',
  776. 'ランクアップ?([神聖石]30個)',
  777. ]
  778. ),
  779. "BA4T" => DiceTable::Table.new(
  780. "[神器:装飾品]表B☆4",
  781. "1D6",
  782. [
  783. 'ヒールグラス P.105',
  784. 'テレポートブレス P.105',
  785. 'ブラッドチェンジャー P.105',
  786. 'ルーンブレス P.105',
  787. 'コンディショナー P.105',
  788. 'ランクアップ?([神聖石]40個)',
  789. ]
  790. ),
  791. "BA5T" => DiceTable::Table.new(
  792. "[神器:装飾品]表B☆5",
  793. "1D1",
  794. [
  795. 'ノーブルスフィア P.105',
  796. ]
  797. ),
  798. }.freeze
  799. 1 register_prefix('\d+DC', 'REV', TABLES.keys)
  800. end
  801. end
  802. end

lib/bcdice/game_system/DoubleCross.rb

100.0% lines covered

96.97% branches covered

123 relevant lines. 123 lines covered and 0 lines missed.
33 total branches, 32 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/arithmetic_evaluator'
  3. 1 require 'bcdice/dice_table/range_table'
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class DoubleCross < Base
  7. # ゲームシステムの識別子
  8. 1 ID = 'DoubleCross'
  9. # ゲームシステム名
  10. 1 NAME = 'ダブルクロス2nd,3rd'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = 'たふるくろす2'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  15. ・判定コマンド(xDX+y@c or xDXc+y)
  16.  "(個数)DX(修正)@(クリティカル値)" もしくは "(個数)DX(クリティカル値)(修正)" で指定します。
  17.  修正値も付けられます。
  18.  例)10dx  10dx+5@8(OD tool式)  5DX7+7-3(疾風怒濤式)
  19. ・各種表
  20.  ・感情表(ET)
  21.   ポジティブとネガティブの両方を振って、表になっている側に○を付けて表示します。
  22.   もちろん任意で選ぶ部分は変更して構いません。
  23. ・ハプニングチャート(HC)
  24. ・RWプロローグチャート ポジティブ (PCP)
  25. ・RWプロローグチャート ネガティブ (PCN)
  26. ・D66ダイスあり
  27. INFO_MESSAGE_TEXT
  28. 1 def initialize(command)
  29. 193 super(command)
  30. 193 @sides_implicit_d = 10
  31. end
  32. 1 register_prefix('\d+DX', 'ET')
  33. # 成功判定コマンドのノード
  34. 1 class DX
  35. 1 include Translate
  36. # ノードを初期化する
  37. # @param [Integer] num ダイス数
  38. # @param [Integer] critical_value クリティカル値
  39. # @param [Integer] modifier 修正値
  40. # @param [Integer] target_value 目標値
  41. 1 def initialize(num, critical_value, modifier, target_value)
  42. 154 @num = num
  43. 154 @critical_value = critical_value
  44. 154 @modifier = modifier
  45. 154 @target_value = target_value
  46. 154 @modifier_str = Format.modifier(@modifier)
  47. 154 @expression = node_expression()
  48. 154 @locale = :ja_jp
  49. end
  50. # 成功判定を行う
  51. # @param randomizer [Randomizer]
  52. # @return [Result] 判定結果
  53. 1 def execute(randomizer)
  54. 154 then: 2 else: 152 if @critical_value < 2
  55. 2 return Result.new("(#{@expression}) > #{translate('DoubleCross.DX.invalid_critical')}")
  56. end
  57. 152 then: 2 else: 150 if @num < 1
  58. 2 return Result.failure("(#{@expression}) > #{translate('DoubleCross.DX.auto_failure')}")
  59. end
  60. # 出目のグループの配列
  61. 150 value_groups = []
  62. # 次にダイスロールを行う際のダイス数
  63. 150 num_of_dice = @num
  64. # 回転数
  65. 150 loop_count = 0
  66. 150 body: 1012 while num_of_dice > 0 && loop_count < CommonCommand::RerollDice::REROLL_LIMIT
  67. 1012 values = randomizer.roll_barabara(num_of_dice, 10)
  68. 1012 value_group = ValueGroup.new(values, @critical_value)
  69. 1012 value_groups.push(value_group)
  70. # 次回はクリティカル発生数と等しい個数のダイスを振る
  71. # [3rd ルールブック1 p. 185]
  72. 1012 num_of_dice = value_group.num_of_critical_occurrences
  73. 1012 loop_count += 1
  74. end
  75. 150 return result(value_groups)
  76. end
  77. 1 private
  78. # 数式表記を返す
  79. # @return [String]
  80. 1 def node_expression
  81. 154 lhs = "#{@num}DX#{@critical_value}#{@modifier_str}"
  82. 154 then: 12 else: 142 return @target_value ? "#{lhs}>=#{@target_value}" : lhs
  83. end
  84. # 判定結果を返す
  85. # @param [Array<ValueGroup>] value_groups 出目のグループの配列
  86. # @return [Result]
  87. 1 def result(value_groups)
  88. 150 r = Result.new
  89. 150 r.fumble = value_groups[0].values.all?(1)
  90. 150 sum = value_groups.map(&:max).sum
  91. 150 then: 10 else: 140 achieved_value = r.fumble? ? 0 : (sum + @modifier)
  92. # ファンブルかどうかを含む達成値の表記
  93. achieved_value_with_if_fumble =
  94. 150 then: 10 if r.fumble?
  95. 10 "#{achieved_value} (#{translate('fumble')})"
  96. else: 140 else
  97. 140 achieved_value.to_s
  98. end
  99. 150 r.critical = value_groups.length > 1
  100. parts = [
  101. 150 "(#{@expression})",
  102. "#{value_groups.join('+')}#{@modifier_str}",
  103. achieved_value_with_if_fumble
  104. ]
  105. 150 else: 138 if @target_value
  106. # 行為判定成功か?
  107. #
  108. # ファンブル時は自動失敗、達成値が目標値以上ならば行為判定成功
  109. then: 12 # [3rd ルールブック1 pp. 186-187]
  110. 12 success = !r.fumble? && (achieved_value >= @target_value)
  111. 12 then: 4 if success
  112. 4 r.success = true
  113. else: 8 else
  114. 8 r.failure = true
  115. end
  116. 12 then: 4 else: 8 compare_result_text = translate(success ? 'success' : 'failure')
  117. 12 parts.push(compare_result_text)
  118. end
  119. 150 r.text = parts.join(' > ')
  120. 150 return r
  121. end
  122. end
  123. # 出目のグループを表すクラス
  124. 1 class ValueGroup
  125. # 出目の配列
  126. # @return [Array<Integer>]
  127. 1 attr_reader :values
  128. # クリティカル値
  129. # @return [Integer]
  130. 1 attr_reader :critical_value
  131. # 出目のグループを初期化する
  132. # @param [Array<Integer>] values 出目の配列
  133. # @param [Integer] critical_value クリティカル値
  134. 1 def initialize(values, critical_value)
  135. 1012 @values = values.sort
  136. 1012 @critical_value = critical_value
  137. end
  138. # 出目のグループの文字列表記を返す
  139. # @return [String]
  140. 1 def to_s
  141. 1012 "#{max}[#{@values.join(',')}]"
  142. end
  143. # 出目のグループ中の最大値を返す
  144. # @return [Integer]
  145. #
  146. # クリティカル値以上の出目が含まれていた場合は10を返す。
  147. # [3rd ルールブック1 pp. 185-186]
  148. 1 def max
  149. 5632 then: 1724 else: 300 @values.any? { |value| critical?(value) } ? 10 : @values.max
  150. end
  151. # クリティカルの発生数を返す
  152. # @return [Integer]
  153. 1 def num_of_critical_occurrences
  154. 3722 @values.count { |value| critical?(value) }
  155. end
  156. 1 private
  157. # クリティカルが発生したかを返す
  158. # @param [Integer] value 出目
  159. # @return [Boolean]
  160. #
  161. # クリティカル値以上の値が出た場合、クリティカルとする。
  162. # [3rd ルールブック1 pp. 185-186]
  163. 1 def critical?(value)
  164. 6318 value >= @critical_value
  165. end
  166. end
  167. # ダイスボット固有コマンドの処理を行う
  168. # @param [String] command コマンド
  169. # @return [String] ダイスボット固有コマンドの結果
  170. # @return [nil] 無効なコマンドだった場合
  171. 1 def eval_game_system_specific_command(command)
  172. 191 then: 154 else: 37 if (dx = parse_dx(command))
  173. 154 return dx.execute(@randomizer)
  174. end
  175. 37 then: 14 else: 23 if self.class::TABLES.key?(command)
  176. 14 return roll_tables(command, self.class::TABLES)
  177. end
  178. 23 then: 20 else: 3 if command == 'ET'
  179. 20 return roll_emotion_table()
  180. end
  181. 3 return nil
  182. end
  183. 1 private
  184. # 成功判定コマンドの構文解析を行う
  185. # @param [String] command コマンド文字列
  186. # @return [DX, nil]
  187. 1 def parse_dx(command)
  188. 191 parse_dx_od(command) || parse_dx_shippu_doto(command)
  189. end
  190. # OD Tool式の成功判定コマンドの正規表現マッチ情報からノードを作る
  191. # @param command [String]
  192. # @return [DX]
  193. 1 def parse_dx_od(command)
  194. 191 parser = Command::Parser.new(/\d+DX/, round_type: round_type)
  195. .enable_critical
  196. .restrict_cmp_op_to(nil, :>=)
  197. 191 parsed = parser.parse(command)
  198. 191 else: 121 then: 70 return nil unless parsed
  199. 121 num = parsed.command.to_i
  200. 121 critical_value = parsed.critical || 10
  201. 121 self.class::DX.new(num, critical_value, parsed.modify_number, parsed.target_number)
  202. end
  203. # 疾風怒濤式の成功判定コマンドの正規表現マッチ情報からノードを作る
  204. # @param command [String]
  205. # @return [DX]
  206. 1 def parse_dx_shippu_doto(command)
  207. 70 parser = Command::Parser.new(/\d+DX\d*/, round_type: round_type)
  208. .restrict_cmp_op_to(nil, :>=)
  209. 70 parsed = parser.parse(command)
  210. 70 else: 33 then: 37 return nil unless parsed
  211. 99 then: 66 else: 0 num, critical_value = parsed.command.split("DX", 2).map { |x| x&.to_i }
  212. 33 critical_value ||= 10
  213. 33 self.class::DX.new(num, critical_value, parsed.modify_number, parsed.target_number)
  214. end
  215. # 感情表を振る
  216. #
  217. # ポジティブとネガティブの両方を振って、表になっている側に○を付ける。
  218. #
  219. # @return [Result]
  220. 1 def roll_emotion_table
  221. 20 pos_result = self.class::POSITIVE_EMOTION_TABLE.roll(@randomizer)
  222. 20 neg_result = self.class::NEGATIVE_EMOTION_TABLE.roll(@randomizer)
  223. 20 positive = @randomizer.roll_once(2) == 1
  224. pos_neg_text =
  225. 20 then: 10 if positive
  226. 10 ["○#{pos_result.content}", neg_result.content]
  227. else: 10 else
  228. 10 [pos_result.content, "○#{neg_result.content}"]
  229. end
  230. 20 name = translate("DoubleCross.ET.name")
  231. output_parts = [
  232. 20 "#{name}(#{pos_result.sum}-#{neg_result.sum})",
  233. pos_neg_text.join(' - ')
  234. ]
  235. 20 return Result.new(output_parts.join(' > '))
  236. end
  237. 1 class << self
  238. 1 private
  239. # @param locale [Symbol]
  240. # @return [RangeTable]
  241. 1 def positive_emotion_table(locale)
  242. 2 DiceTable::RangeTable.new(
  243. I18n.translate("DoubleCross.ET.positive.name", locale: locale),
  244. "1D100",
  245. [
  246. # [0, '傾倒(けいとう)'],
  247. [1..5, I18n.translate("DoubleCross.ET.positive.items.1_5", locale: locale)],
  248. [6..10, I18n.translate("DoubleCross.ET.positive.items.6_10", locale: locale)],
  249. [11..15, I18n.translate("DoubleCross.ET.positive.items.11_15", locale: locale)],
  250. [16..20, I18n.translate("DoubleCross.ET.positive.items.16_20", locale: locale)],
  251. [21..25, I18n.translate("DoubleCross.ET.positive.items.21_25", locale: locale)],
  252. [26..30, I18n.translate("DoubleCross.ET.positive.items.26_30", locale: locale)],
  253. [31..35, I18n.translate("DoubleCross.ET.positive.items.31_35", locale: locale)],
  254. [36..40, I18n.translate("DoubleCross.ET.positive.items.36_40", locale: locale)],
  255. [41..45, I18n.translate("DoubleCross.ET.positive.items.41_45", locale: locale)],
  256. [46..50, I18n.translate("DoubleCross.ET.positive.items.46_50", locale: locale)],
  257. [51..55, I18n.translate("DoubleCross.ET.positive.items.51_55", locale: locale)],
  258. [56..60, I18n.translate("DoubleCross.ET.positive.items.56_60", locale: locale)],
  259. [61..65, I18n.translate("DoubleCross.ET.positive.items.61_65", locale: locale)],
  260. [66..70, I18n.translate("DoubleCross.ET.positive.items.66_70", locale: locale)],
  261. [71..75, I18n.translate("DoubleCross.ET.positive.items.71_75", locale: locale)],
  262. [76..80, I18n.translate("DoubleCross.ET.positive.items.76_80", locale: locale)],
  263. [81..85, I18n.translate("DoubleCross.ET.positive.items.81_85", locale: locale)],
  264. [86..90, I18n.translate("DoubleCross.ET.positive.items.86_90", locale: locale)],
  265. [91..95, I18n.translate("DoubleCross.ET.positive.items.91_95", locale: locale)],
  266. [96..100, I18n.translate("DoubleCross.ET.positive.items.96_100", locale: locale)],
  267. # [101, '懐旧(かいきゅう)'],
  268. # [102, '任意(にんい)'],
  269. ]
  270. )
  271. end
  272. # @param locale [Symbol]
  273. # @return [RangeTable]
  274. 1 def negative_emotion_table(locale)
  275. 2 DiceTable::RangeTable.new(
  276. I18n.translate("DoubleCross.ET.negative.name", locale: locale),
  277. "1D100",
  278. [
  279. # [0, '侮蔑(ぶべつ)'],
  280. [1..5, I18n.translate("DoubleCross.ET.negative.items.1_5", locale: locale)],
  281. [6..10, I18n.translate("DoubleCross.ET.negative.items.6_10", locale: locale)],
  282. [11..15, I18n.translate("DoubleCross.ET.negative.items.11_15", locale: locale)],
  283. [16..20, I18n.translate("DoubleCross.ET.negative.items.16_20", locale: locale)],
  284. [21..25, I18n.translate("DoubleCross.ET.negative.items.21_25", locale: locale)],
  285. [26..30, I18n.translate("DoubleCross.ET.negative.items.26_30", locale: locale)],
  286. [31..35, I18n.translate("DoubleCross.ET.negative.items.31_35", locale: locale)],
  287. [36..40, I18n.translate("DoubleCross.ET.negative.items.36_40", locale: locale)],
  288. [41..45, I18n.translate("DoubleCross.ET.negative.items.41_45", locale: locale)],
  289. [46..50, I18n.translate("DoubleCross.ET.negative.items.46_50", locale: locale)],
  290. [51..55, I18n.translate("DoubleCross.ET.negative.items.51_55", locale: locale)],
  291. [56..60, I18n.translate("DoubleCross.ET.negative.items.56_60", locale: locale)],
  292. [61..65, I18n.translate("DoubleCross.ET.negative.items.61_65", locale: locale)],
  293. [66..70, I18n.translate("DoubleCross.ET.negative.items.66_70", locale: locale)],
  294. [71..75, I18n.translate("DoubleCross.ET.negative.items.71_75", locale: locale)],
  295. [76..80, I18n.translate("DoubleCross.ET.negative.items.76_80", locale: locale)],
  296. [81..85, I18n.translate("DoubleCross.ET.negative.items.81_85", locale: locale)],
  297. [86..90, I18n.translate("DoubleCross.ET.negative.items.86_90", locale: locale)],
  298. [91..95, I18n.translate("DoubleCross.ET.negative.items.91_95", locale: locale)],
  299. [96..100, I18n.translate("DoubleCross.ET.negative.items.96_100", locale: locale)],
  300. # [101, '無関心(むかんしん)'],
  301. # [102, '任意(にんい)'],
  302. ]
  303. ).freeze
  304. end
  305. 1 def translate_tables(locale)
  306. {
  307. 2 "HC" => DiceTable::RangeTable.from_i18n("DoubleCross.HC", locale),
  308. "PCP" => DiceTable::Table.from_i18n("DoubleCross.PCP", locale),
  309. "PCN" => DiceTable::Table.from_i18n("DoubleCross.PCN", locale),
  310. }
  311. end
  312. end
  313. # 感情表(ポジティブ)
  314. 1 POSITIVE_EMOTION_TABLE = positive_emotion_table(:ja_jp).freeze
  315. # 感情表(ネガティブ)
  316. 1 NEGATIVE_EMOTION_TABLE = negative_emotion_table(:ja_jp).freeze
  317. 1 TABLES = translate_tables(:ja_jp).freeze
  318. 1 register_prefix('\d+DX', TABLES.keys)
  319. end
  320. end
  321. end

lib/bcdice/game_system/DoubleCross_Korean.rb

100.0% lines covered

100.0% branches covered

20 relevant lines. 20 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/DoubleCross"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class DoubleCross_Korean < DoubleCross
  6. # ゲームシステムの識別子
  7. 1 ID = 'DoubleCross:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '더블크로스2nd,3rd'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:더블크로스'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・판정 커맨드(xDX+y@c or xDXc+y)
  15.  "(개수)DX(수정)@(크리티컬치)" 혹은 "(개수)DX(크리티컬치)(수정)" 으로 지정합니다.
  16.  수정치도 붙일 수 있습니다.
  17.  예)10dx  10dx+5@8(OD tool식)  5DX7+7-3(질풍노도식)
  18. ・각종표
  19.  ・감정표(ET)
  20.   포지티브와 네거티브 양쪽을 굴려, 겉으로 나타는 쪽에 O를 붙여 표시합니다.
  21.   물론 임의로 정하는 부분을 변경해도 괜찮습니다.
  22. ・해프닝차트(HC)
  23. ・RW프롤로그차트 포지티브(PCP)
  24. ・RW프롤로그차트 네거티브(PCN)
  25. ・D66다이스 있음
  26. INFO_MESSAGE_TEXT
  27. 1 register_prefix_from_super_class()
  28. 1 def initialize(command)
  29. 92 super(command)
  30. 92 @locale = :ko_kr
  31. end
  32. 1 class DX < DoubleCross::DX
  33. # @param (see DoubleCross::DX#initialize)
  34. 1 def initialize(num, critical_value, modifier, target_value)
  35. 76 super(num, critical_value, modifier, target_value)
  36. 76 @locale = :ko_kr
  37. end
  38. end
  39. # 感情表(ポジティブ)
  40. 1 POSITIVE_EMOTION_TABLE = positive_emotion_table(:ko_kr).freeze
  41. # 感情表(ネガティブ)
  42. 1 NEGATIVE_EMOTION_TABLE = negative_emotion_table(:ko_kr).freeze
  43. 1 TABLES = translate_tables(:ko_kr).freeze
  44. 1 register_prefix('\d+DX', TABLES.keys)
  45. end
  46. end
  47. end

lib/bcdice/game_system/Dracurouge.rb

100.0% lines covered

90.63% branches covered

132 relevant lines. 132 lines covered and 0 lines missed.
32 total branches, 29 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Dracurouge < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Dracurouge'
  7. # ゲームシステム名
  8. 1 NAME = 'ドラクルージュ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'とらくるうしゆ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・行い判定(DRx+y)
  14.  x:振るサイコロの数(省略時4)、y:渇き修正(省略時0)
  15.  例) DR DR6 DR+1 DR5+2
  16. ・抗い判定(DRRx)
  17.  x:振るサイコロの数
  18.  例) DRR3
  19. ・原風景表(ST)、叙勲表(CO)、叙勲後表(CA)、遥か過去表(EP)
  20.  原罪表(OS)、受難表(PN)、近況表(RS)、平和な過去表(PP)
  21. ・堕落表(CTx) x:渇き (例) CT3
  22. ・堕落の兆し表(CS)、拡張・堕落の兆し表(ECS)
  23. ・絆内容決定表(BT)
  24. ・反応表(RTxy)x:血統、y:道 xy省略で一括表示
  25.  血統 D:ドラク、R:ローゼンブルク、H:ヘルズガルド、M:ダストハイム
  26.     A:アヴァローム N:ノスフェラス、G:ゲイズヴァルト、K:カインシルト
  27.  道 F:領主、G:近衛、R:遍歴、W:賢者、J:狩人、N:夜獣
  28.    E:将軍、B:僧正、H:空駆、K:船長、L:寵童、V:仲立、U:技師、D:博士
  29.    S:星読、G2:後見
  30.  例)RT(一括表示)、RTDF(ドラクの領主)、RTAG2(アヴァロームの後見人)
  31. ・異端の反応表(HRTxy)x:血統、y:道 xy省略で一括表示
  32.  血統 L:異端卿、V:ヴルコラク、N:ナハツェーラ、K:カルンシュタイン
  33.     G:グリマルキン、S:ストリガ、M:メリュジーヌ、F:フォーン
  34.     H:ホムンクルス、E:エナメルム、S2:サングィナリエ、A:アールヴ
  35.     V2:ヴィーヴル、L2:ルーガルー、A2:アルラウネ、F2:フリッガ
  36.  道 W:野伏、N:流浪、S:密使、H:魔女、F:剣士、X:検体
  37.  例)HRT(一括表示)、HRTVW(ヴルコラクの野伏)、HRTF2X(フリッガの検体)
  38. ・D66ダイスあり
  39. MESSAGETEXT
  40. 1 def initialize(command)
  41. 260 super(command)
  42. 260 @d66_sort_type = D66SortType::NO_SORT
  43. end
  44. 1 def eval_game_system_specific_command(command)
  45. 258 roll_conduct_dice(command) ||
  46. roll_resist_dice(command) ||
  47. getReactionDiceCommandResult(command) ||
  48. getHeresyReactionDiceCommandResult(command) ||
  49. getCorruptionDiceCommandResult(command) ||
  50. roll_tables(command, self.class::TABLES)
  51. end
  52. 1 private
  53. # 行い判定 (DRx+y)
  54. 1 def roll_conduct_dice(command)
  55. 258 m = /^DR(\d*[1-9])?(\+\d+)?$/.match(command)
  56. 258 else: 30 then: 228 unless m
  57. 228 return nil
  58. end
  59. 30 then: 14 else: 16 dice_count = m[1]&.to_i || 4
  60. 30 thirsty_point = m[2].to_i
  61. 30 dice_list = @randomizer.roll_barabara(dice_count, 6).sort
  62. 30 glory_dice = count_glory_dice(dice_list)
  63. 30 dice_list += Array.new(glory_dice, 10)
  64. 30 calculation_process = apply_thirsty_point(dice_list, thirsty_point)
  65. sequence = [
  66. 30 "(#{command})",
  67. "#{dice_count}D6#{Format.modifier(thirsty_point)}",
  68. calculation_process,
  69. "[ #{dice_list.join(', ')} ]",
  70. ].compact
  71. 30 return sequence.join(" > ")
  72. end
  73. 1 def count_glory_dice(dice_list)
  74. 30 one_count = dice_list.count(1)
  75. 30 six_count = dice_list.count(6)
  76. 30 return (one_count / 2) + (six_count / 2)
  77. end
  78. 1 def apply_thirsty_point(dice_list, thirsty_point)
  79. 30 then: 24 else: 6 return nil if thirsty_point == 0
  80. 18 idx = dice_list.rindex { |i| i <= 6 }
  81. 6 text_list = dice_list.map(&:to_s)
  82. 6 text_list[idx] += "+#{thirsty_point}"
  83. 6 dice_list[idx] += thirsty_point
  84. 6 return "[ #{text_list.join(', ')} ]"
  85. end
  86. # 抗い判定 (DRRx)
  87. 1 def roll_resist_dice(command)
  88. 228 m = /^DRR(\d+)$/.match(command)
  89. 228 else: 6 then: 222 unless m
  90. 222 return nil
  91. end
  92. 6 dice_count = m[1].to_i
  93. 6 then: 0 else: 6 dice_count = 4 if dice_count == 0
  94. 6 dice_list = @randomizer.roll_barabara(dice_count, 6).sort
  95. 6 total = dice_list.sum()
  96. 6 return "(#{command}) > #{dice_count}D6 > [ #{dice_list.join(', ')} ] > #{total}"
  97. end
  98. 1 def getReactionDiceCommandResult(command)
  99. 222 else: 44 then: 178 return nil unless command =~ /^RT((\w\d*)(\w\d*))?/
  100. 44 typeText1 = Regexp.last_match(2)
  101. 44 typeText2 = Regexp.last_match(3)
  102. 44 name = translate("Dracurouge.RT.name")
  103. 44 blood = translate("Dracurouge.RT.blood")
  104. 44 style = translate("Dracurouge.RT.style")
  105. 44 return getReactionText(name, typeText1, typeText2, blood, style)
  106. end
  107. 1 def getHeresyReactionDiceCommandResult(command)
  108. 179 else: 110 then: 69 return nil unless command =~ /^HRT((\w\d*)(\w\d*))?/
  109. 110 typeText1 = Regexp.last_match(2)
  110. 110 typeText2 = Regexp.last_match(3)
  111. 110 name = translate("Dracurouge.HRT.name")
  112. 110 blood = translate("Dracurouge.HRT.blood")
  113. 110 style = translate("Dracurouge.HRT.style")
  114. 110 return getReactionText(name, typeText1, typeText2, blood, style)
  115. end
  116. 1 def getReactionText(name, typeText1, typeText2, infos1, infos2)
  117. 154 else: 153 then: 1 return nil unless checkTypeText(typeText1, infos1)
  118. 153 else: 153 then: 0 return nil unless checkTypeText(typeText2, infos2)
  119. 153 ten_value = @randomizer.roll_once(6)
  120. 153 one_value = @randomizer.roll_once(6)
  121. 153 number = "#{ten_value}#{one_value}"
  122. 153 isBefore = (ten_value < 4)
  123. 153 then: 78 else: 75 infos = isBefore ? infos1 : infos2
  124. 153 then: 78 else: 75 typeText = (isBefore ? typeText1 : typeText2)
  125. 153 then: 78 else: 75 index = (one_value - 1) + (isBefore ? (ten_value - 1) : (ten_value - 4)) * 6
  126. 153 debug("index", index)
  127. 153 then: 16 if typeText.nil?
  128. 16 resultText = getReactionTextFull(infos, index)
  129. else: 137 else
  130. 137 info = infos[typeText.to_sym]
  131. 137 then: 0 else: 137 return nil if info.nil?
  132. 137 resultText = getReactionTex(info, index)
  133. end
  134. 153 return "#{name}(#{number}) > #{resultText}"
  135. end
  136. 1 def checkTypeText(typeText, infos)
  137. 307 then: 32 else: 275 return true if typeText.nil?
  138. 275 return infos.keys.include?(typeText.to_sym)
  139. end
  140. 1 def getReactionTextFull(infos, index)
  141. 16 resultTexts = []
  142. 16 infos.each_value do |info|
  143. 170 resultTexts << getReactionTex(info, index)
  144. end
  145. 16 return resultTexts.join('/')
  146. end
  147. 1 def getReactionTex(info, index)
  148. 307 typeName = info[:name]
  149. 307 text = info[:table][index]
  150. 307 return "#{typeName}:#{text}"
  151. end
  152. 1 def getCorruptionDiceCommandResult(command)
  153. 69 else: 14 then: 55 return nil unless command =~ /^CT(\d+)$/
  154. 14 modify = Regexp.last_match(1).to_i
  155. 14 name = translate("Dracurouge.CT.name")
  156. table =
  157. [
  158. 14 [0, translate("Dracurouge.CT.table.0")],
  159. [1, translate("Dracurouge.CT.table.1")],
  160. [3, translate("Dracurouge.CT.table.3")],
  161. [5, translate("Dracurouge.CT.table.5")],
  162. [6, translate("Dracurouge.CT.table.6")],
  163. [7, translate("Dracurouge.CT.table.7")],
  164. [8, translate("Dracurouge.CT.table.8")],
  165. [99, translate("Dracurouge.CT.table.99")],
  166. ]
  167. 14 dice_list = @randomizer.roll_barabara(2, 6)
  168. 14 number = dice_list.sum()
  169. 14 number_text = dice_list.join(",")
  170. 14 index = (number - modify)
  171. 14 debug('index', index)
  172. 14 text = get_table_by_number(index, table)
  173. 14 return "2D6[#{number_text}]-#{modify} > #{name}(#{index}) > #{text}"
  174. end
  175. 1 class YearTable
  176. # @param key [String]
  177. # @param locale [Symbol]
  178. # @param years [Array<String>]
  179. # @return [YearTable]
  180. 1 def self.from_i18n(key, locale, years)
  181. 12 table = I18n.translate(key, locale: locale, raise: true)
  182. 12 items = table[:items].zip(years)
  183. 12 return new(table[:name], table[:year_title], items)
  184. end
  185. # @param name [String]
  186. # @param year_title [String]
  187. # @param items [Array<Array<(String, String)>>]
  188. 1 def initialize(name, year_title, items)
  189. 12 @name = name
  190. 12 @year_title = year_title
  191. 12 @items = items.freeze
  192. end
  193. # @param randomizer [Randomizer]
  194. # @return [String]
  195. 1 def roll(randomizer)
  196. 32 tens, ones = randomizer.roll_barabara(2, 6)
  197. 32 index = (tens - 1) * 6 + (ones - 1)
  198. 32 text, year_expr = @items[index]
  199. 73 interim_expr = year_expr.gsub(/\d+D6+/) { |expr| roll_d6x(expr, randomizer) }
  200. 32 year = ArithmeticEvaluator.eval(interim_expr.gsub("×", "*"))
  201. 32 "#{@name}(#{tens}#{ones}) > #{text} > #{@year_title}:#{year_expr} > (#{interim_expr}) > #{@year_title}:#{year}年"
  202. end
  203. 1 private
  204. # D66と同様の形式でD666などにも対応したダイスロール
  205. #
  206. # @param expr [String]
  207. # @param randomizer [Randomizer]
  208. # @return [Integer]
  209. 1 def roll_d6x(expr, randomizer)
  210. 41 times, sides = expr.split("D", 2)
  211. 41 times = times.to_i
  212. 41 list = Array.new(times) do
  213. 61 randomizer.roll_barabara(sides.length, 6)
  214. .reverse # テスト系の互換性のために反転する
  215. 65 .map.with_index { |x, idx| x * (10**idx) }
  216. .sum()
  217. end
  218. 41 return list.sum()
  219. end
  220. end
  221. 1 class << self
  222. 1 private
  223. 1 def translate_tables(locale)
  224. {
  225. 2 "CO" => YearTable.from_i18n(
  226. "Dracurouge.table.CO",
  227. locale,
  228. [
  229. "7+1D6×1D6",
  230. "7+1D6×1D6",
  231. "7+1D6×1D6",
  232. "7+1D6×1D6",
  233. "7+1D6×1D6",
  234. "7+1D6×1D6",
  235. "7+1D6×1D6",
  236. "10+2D6",
  237. "7+1D6×1D6",
  238. "14+1D6×1D6",
  239. "7+1D6×1D6",
  240. "10+1D6×1D6",
  241. "7+1D6×1D6",
  242. "10+2D6",
  243. "7+1D6×1D6",
  244. "14+1D6×1D6",
  245. "10+2D6",
  246. "7+1D6×1D6",
  247. "14+1D6×1D6",
  248. "18+1D6×1D6",
  249. "10+2D6",
  250. "7+1D6×1D6",
  251. "7+1D6×1D6",
  252. "7+1D6×1D6",
  253. "7+1D6×1D6",
  254. "30+1D6×1D6",
  255. "14+1D6×1D6",
  256. "7+1D6×1D6",
  257. "14+1D6×1D6",
  258. "10+2D6",
  259. "14+1D6×1D6",
  260. "14+1D6×1D6",
  261. "7+4D6",
  262. "14+1D6×1D6",
  263. "7+1D6×1D6",
  264. "7+1D6×1D6",
  265. ]
  266. ),
  267. "CA" => YearTable.from_i18n(
  268. "Dracurouge.table.CA",
  269. locale,
  270. [
  271. "2D6×10",
  272. "1D6×1D6",
  273. "1D6×1D6",
  274. "2D6×5",
  275. "2D6×10",
  276. "1D6×1D6",
  277. "2D6×10",
  278. "1D6×5",
  279. "2D6×10",
  280. "2D6×3",
  281. "1D6×1D6",
  282. "1D6×1D6",
  283. "2D6×10",
  284. "2D6×10",
  285. "2D6×20",
  286. "2D6×10",
  287. "2D6×20",
  288. "1D6×1D6",
  289. "1D6×3",
  290. "1D6×1D6",
  291. "1D6×5",
  292. "2D6×10",
  293. "1D6×1D6",
  294. "2D6×10",
  295. "2D6",
  296. "1D6×1D6",
  297. "2D6",
  298. "1D6×1D6",
  299. "2D6×20",
  300. "2D6×10",
  301. "1D6×1D6",
  302. "2D6×50",
  303. "2D6×10",
  304. "1D6×1D6",
  305. "2D6×5",
  306. "1D6×1D6",
  307. ]
  308. ),
  309. "EP" => YearTable.from_i18n(
  310. "Dracurouge.table.EP",
  311. locale,
  312. [
  313. "1D66+1300",
  314. "1D666",
  315. "1D666",
  316. "1D666",
  317. "1D66+1250",
  318. "1D666",
  319. "3D6×100",
  320. "2D6×100",
  321. "1D66+1210",
  322. "1D666",
  323. "2D6×100",
  324. "3D6×100",
  325. "1D66+1300",
  326. "2D6×100",
  327. "1D6+1250",
  328. "1D666",
  329. "1D666",
  330. "1D666",
  331. "1D66+1250",
  332. "2D6×100",
  333. "1D666",
  334. "3D6×100",
  335. "2D6×100",
  336. "2D6×100",
  337. "1D6×150",
  338. "2D6×100",
  339. "1D66+1250",
  340. "1D66+400",
  341. "1212",
  342. "2D6×100",
  343. "2D6×100",
  344. "1D66×10",
  345. "3D6×100",
  346. "3D6×100",
  347. "1D66+1300",
  348. "1D66+1833",
  349. ]
  350. ),
  351. "OS" => YearTable.from_i18n(
  352. "Dracurouge.table.OS",
  353. locale,
  354. [
  355. "7+1D6×1D6",
  356. "7+1D6×1D6",
  357. "7+1D6×1D6",
  358. "7+1D6×1D6",
  359. "7+1D6×1D6",
  360. "7+1D6×1D6",
  361. "7+1D6×1D6",
  362. "7+1D6×1D6",
  363. "7+1D6×1D6",
  364. "13+1D6×1D6",
  365. "7+1D6×1D6",
  366. "13+1D6×1D6",
  367. "7+1D6×1D6",
  368. "13+1D6×1D6",
  369. "13+1D6×1D6",
  370. "13+1D6×1D6",
  371. "7+1D6×1D6",
  372. "7+1D6×1D6",
  373. "10+1D6×1D6",
  374. "7+1D6×1D6",
  375. "15+1D6×1D6",
  376. "6+2D6",
  377. "7+1D6×1D6",
  378. "7+1D6×1D6",
  379. "13+1D6×1D6",
  380. "35+1D6×1D6",
  381. "9+2D6",
  382. "13+1D6×1D6",
  383. "9+2D6",
  384. "6+2D6",
  385. "7+1D6×1D6",
  386. "7+2D6",
  387. "7+1D6×1D5",
  388. "7+1D6×1D6",
  389. "13+1D6×1D6",
  390. "7+1D6×1D6",
  391. ]
  392. ),
  393. "RS" => YearTable.from_i18n(
  394. "Dracurouge.table.RS",
  395. locale,
  396. [
  397. "2D6×10",
  398. "1D6×1D6",
  399. "1D6×1D6",
  400. "1D6×1D6",
  401. "3D6×30",
  402. "3D6×30",
  403. "2D6×10",
  404. "2D6×10",
  405. "2D6×10",
  406. "2D6×10",
  407. "2D6×20",
  408. "1D6×1D6",
  409. "1D6×1D6",
  410. "1D6×1D6",
  411. "1",
  412. "2D6×10",
  413. "2D6×20",
  414. "1D6×1D6",
  415. "1D6×1D6",
  416. "3D6×30",
  417. "3D6×20",
  418. "1D6×1D6",
  419. "3D6×30",
  420. "3D6×20",
  421. "1D6×1D6",
  422. "1D6×1D6",
  423. "1D6×1D6",
  424. "1D6×1D6",
  425. "1D6×10",
  426. "2D6×10",
  427. "3D6×50",
  428. "1D6×1D6",
  429. "3D6×20",
  430. "2D6×10",
  431. "1D6×1D6",
  432. "3D6×50",
  433. ]
  434. ),
  435. "PP" => YearTable.from_i18n(
  436. "Dracurouge.table.PP",
  437. locale,
  438. [
  439. "8+2D6",
  440. "6+2D6",
  441. "7+1D6×1D6",
  442. "15+1D6×1D6",
  443. "7+1D6×1D6",
  444. "7+1D6×1D6",
  445. "7+1D6×1D6",
  446. "7+1D6×1D6",
  447. "7+1D6×1D6",
  448. "7+1D6×1D6",
  449. "7+1D6×1D6",
  450. "7+1D6×1D6",
  451. "6+2D6",
  452. "7+1D6×1D6",
  453. "9+2D6",
  454. "15+1D6×1D6",
  455. "9+3D6",
  456. "7+1D6×1D6",
  457. "10+1D6×1D6",
  458. "9+2D6",
  459. "9+2D6",
  460. "9+3D6",
  461. "6+2D6",
  462. "7+1D6×1D6",
  463. "7+1D6×1D6",
  464. "7+1D6×1D6",
  465. "6+2D6",
  466. "10+1D6×1D6",
  467. "7+1D6×1D6",
  468. "12+1D6×1D6",
  469. "15+1D6×1D6",
  470. "9+3D6",
  471. "7+1D6×1D6",
  472. "7+1D6×1D6",
  473. "7+1D6×1D6",
  474. "12+4D6",
  475. ]
  476. ),
  477. "ST" => DiceTable::D66Table.from_i18n("Dracurouge.table.ST", locale),
  478. "PN" => DiceTable::D66Table.from_i18n("Dracurouge.table.PN", locale),
  479. "CS" => DiceTable::Table.from_i18n("Dracurouge.table.CS", locale),
  480. "ECS" => DiceTable::D66Table.from_i18n("Dracurouge.table.ECS", locale),
  481. "BT" => DiceTable::Table.from_i18n("Dracurouge.table.BT", locale),
  482. }
  483. end
  484. end
  485. 1 TABLES = translate_tables(:ja_jp)
  486. 1 register_prefix('DR', 'RT', 'HRT', 'CT', TABLES.keys)
  487. end
  488. end
  489. end

lib/bcdice/game_system/Dracurouge_Korean.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/Dracurouge"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Dracurouge_Korean < Dracurouge
  6. # ゲームシステムの識別子
  7. 1 ID = 'Dracurouge:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '드라크루주'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:드라크루주'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~MESSAGETEXT
  14. ・행동판정(DRx+y)
  15.  x:굴리는 주사위의 수(생략시4), y:갈증수정(생략시0)
  16.  예) DR DR6 DR+1 DR5+2
  17. ・저항판정(DRRx)
  18.  x:굴리는 주사위의
  19.  예) DRR3
  20. ・原風景表(ST), 叙勲表(CO), 叙勲後表(CA), 遥か過去表(EP)
  21.  原罪表(OS), 受難表(PN), 近況表(RS), 平和な過去表(PP)
  22. ・타락표(CTx) x:갈증(예) CT3
  23. ・타락의 전조표(CS), 拡張・堕落の兆し表(ECS)
  24. ・인연 내용 결정표(BT)
  25. ・반응표(RTxy)x:혈통, y:길 xy생략으로 일괄표시
  26.   혈통 D:드라크, R:로젠부르크, H:헬스가르드, M:더스트하임,
  27.      A:아발롬 N:노스페라스
  28.   길  F:영주, G:근위, R:방랑, W:현자, J:사냥꾼, N:야수
  29.  예)RT(일괄표시), RTDF(드라크 영주), RTAN(아발롬 야수)
  30. ・異端の反応表(HRTxy)x:血統, y:道 xy省略で一括表示
  31.  血統 L:異端卿, V:ヴルコラク, N:ナハツェーラ, K:カルンシュタイン
  32.     G:グリマルキン, S:ストリガ, M:メリュジーヌ, F:フォーン
  33.     H:ホムンクルス, E:エナメルム, S2:サングィナリエ, A:アールヴ
  34.     V2:ヴィーヴル, L2:ルーガルー, A2:アルラウネ, F2:フリッガ
  35.  道 W:野伏, N:流浪, S:密使, H:魔女, F:剣士, X:検体
  36. ・D66 다이스 있음
  37. MESSAGETEXT
  38. 1 register_prefix_from_super_class()
  39. 1 def initialize(command)
  40. 113 super(command)
  41. 113 @locale = :ko_kr
  42. end
  43. 1 TABLES = translate_tables(:ko_kr)
  44. end
  45. end
  46. end

lib/bcdice/game_system/DungeonsAndDragons.rb

100.0% lines covered

100.0% branches covered

7 relevant lines. 7 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class DungeonsAndDragons < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'DungeonsAndDragons'
  7. # ゲームシステム名
  8. 1 NAME = 'ダンジョンズ&ドラゴンズ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'たんしよんすあんととらこんす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = "※このダイスボットは部屋のシステム名表示用となります。\n"
  13. end
  14. end
  15. end

lib/bcdice/game_system/DungeonsAndDragons5.rb

99.29% lines covered

95.0% branches covered

141 relevant lines. 140 lines covered and 1 lines missed.
60 total branches, 57 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class DungeonsAndDragons5 < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'DungeonsAndDragons5'
  7. # ゲームシステム名
  8. 1 NAME = 'ダンジョンズ&ドラゴンズ第5版'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'たんしよんすあんととらこんす5'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・攻撃ロール AT[x][@c][>=t][y]
  14.  x:+-修正。省略可。
  15.  c:クリティカル値。省略可。
  16.  t:敵のアーマークラス。>=を含めて省略可。
  17.  y:有利(A), 不利(D)。省略可。
  18.  ファンブル/失敗/成功/クリティカル を自動判定。
  19.  例)AT AT>=10 AT+5>=18 AT-3>=16 ATA AT>=10A AT+3>=18A AT-3>=16 ATD AT>=10D AT+5>=18D AT-5>=16D
  20.   AT@19 AT+5@18 AT-2@19>=15
  21. ・能力値判定 AR[x][>=t][y]
  22.  攻撃ロールと同様。失敗/成功を自動判定。
  23.  例)AR AR>=10 AR+5>=18 AR-3>=16 ARA AR>=10A AR+3>=18A AR-3>=16 ARD AR>=10D AR+5>=18D AR-5>=16D
  24. ・両手持ちのダメージ 2HnDx[m]
  25.  n:ダイスの個数
  26.  x:ダイスの面数
  27.  m:+-修正。省略可。
  28.  パラディンとファイターの武器の両手持ちによるダメージダイスの1,2の出目の振り直しを行います。
  29.  例)2H3D6 2H1D10+3 2H2D8-1
  30. INFO_MESSAGE_TEXT
  31. 1 register_prefix('AT([+-]\d+)?(@\d+)?(>=\d+)?[AD]?', 'AR([+-]\d+)?(>=\d+)?[AD]?', '2H(\d+)D(\d+)([+-]\d+)?')
  32. 1 def initialize(command)
  33. 54 super(command)
  34. 54 @sort_barabara_dice = false # バラバラロール(Bコマンド)でソート無
  35. end
  36. 1 def eval_game_system_specific_command(command)
  37. 54 attack_roll(command) || ability_roll(command) || twohands_damage_roll(command)
  38. end
  39. 1 def number_with_sign_from_int(number)
  40. 72 then: 32 if number == 0
  41. 32 else: 40 return ""
  42. 40 then: 20 elsif number > 0
  43. 20 return "+#{number}"
  44. else: 20 else
  45. 20 return number.to_s
  46. end
  47. end
  48. # 攻撃ロール
  49. 1 def attack_roll(command)
  50. 54 m = /^AT([-+]\d+)?(@(\d+))?(>=(\d+))?([AD]?)/.match(command)
  51. 54 else: 30 then: 24 unless m
  52. 24 return nil
  53. end
  54. 30 modify = m[1].to_i
  55. 30 critical_no = m[3].to_i
  56. 30 difficulty = m[5].to_i
  57. 30 advantage = m[6]
  58. 30 usedie = 0
  59. 30 roll_die = ""
  60. 30 dice_command = "AT#{number_with_sign_from_int(modify)}"
  61. 30 then: 6 if critical_no > 0
  62. 6 dice_command += "@#{critical_no}"
  63. else: 24 else
  64. 24 critical_no = 20
  65. end
  66. 30 then: 22 else: 8 if difficulty > 0
  67. 22 dice_command += ">=#{difficulty}"
  68. end
  69. 30 else: 20 then: 10 unless advantage.empty?
  70. 10 dice_command += advantage.to_s
  71. end
  72. 30 output = ["(#{dice_command})"]
  73. 30 then: 20 if advantage.empty?
  74. 20 usedie = @randomizer.roll_once(20)
  75. 20 roll_die = usedie
  76. else: 10 else
  77. 10 dice = @randomizer.roll_barabara(2, 20)
  78. 10 roll_die = "[" + dice.join(",") + "]"
  79. 10 then: 5 if advantage == "A"
  80. 5 usedie = dice.max
  81. else: 5 else
  82. 5 usedie = dice.min
  83. end
  84. end
  85. 30 then: 12 if modify != 0
  86. 12 output.push("#{roll_die}#{number_with_sign_from_int(modify)}")
  87. 12 output.push((usedie + modify).to_s)
  88. else: 18 else
  89. 18 else: 12 then: 6 unless advantage.empty?
  90. 6 output.push(roll_die)
  91. end
  92. 18 output.push(usedie.to_s)
  93. end
  94. 30 result = Result.new
  95. 30 then: 10 if usedie >= critical_no
  96. 10 result.critical = true
  97. 10 result.success = true
  98. 10 else: 20 output.push("クリティカル")
  99. 20 then: 4 elsif usedie == 1
  100. 4 result.fumble = true
  101. 4 else: 16 output.push("ファンブル")
  102. 16 then: 13 else: 3 elsif difficulty > 0
  103. 13 then: 6 if usedie + modify >= difficulty
  104. 6 result.success = true
  105. 6 output.push("成功")
  106. else: 7 else
  107. 7 output.push("失敗")
  108. end
  109. end
  110. 30 Result.new.tap do |r|
  111. 30 r.text = output.join(" > ")
  112. 30 then: 30 else: 0 if result
  113. 30 then: 27 else: 3 if difficulty > 0 || result.critical? || result.fumble?
  114. 27 r.condition = result.success?
  115. end
  116. 30 r.critical = result.critical?
  117. 30 r.fumble = result.fumble?
  118. end
  119. end
  120. end
  121. # 能力値ロール
  122. 1 def ability_roll(command)
  123. 24 m = /^AR([-+]\d+)?(>=(\d+))?([AD]?)/.match(command)
  124. 24 else: 18 then: 6 unless m
  125. 6 return nil
  126. end
  127. 18 modify = m[1].to_i
  128. 18 difficulty = m[3].to_i
  129. 18 advantage = m[4]
  130. 18 usedie = 0
  131. 18 roll_die = ""
  132. 18 dice_command = "AR#{number_with_sign_from_int(modify)}"
  133. 18 then: 13 else: 5 if difficulty > 0
  134. 13 dice_command += ">=#{difficulty}"
  135. end
  136. 18 else: 8 then: 10 unless advantage.empty?
  137. 10 dice_command += advantage.to_s
  138. end
  139. 18 output = ["(#{dice_command})"]
  140. 18 then: 8 if advantage.empty?
  141. 8 usedie = @randomizer.roll_once(20)
  142. 8 roll_die = usedie
  143. else: 10 else
  144. 10 dice = @randomizer.roll_barabara(2, 20)
  145. 10 roll_die = "[" + dice.join(",") + "]"
  146. 10 then: 5 if advantage == "A"
  147. 5 usedie = dice.max
  148. else: 5 else
  149. 5 usedie = dice.min
  150. end
  151. end
  152. 18 then: 6 if modify != 0
  153. 6 output.push("#{roll_die}#{number_with_sign_from_int(modify)}")
  154. 6 output.push((usedie + modify).to_s)
  155. else: 12 else
  156. 12 else: 6 then: 6 unless advantage.empty?
  157. 6 output.push(roll_die)
  158. end
  159. 12 output.push(usedie.to_s)
  160. end
  161. 18 result = Result.new
  162. 18 then: 13 else: 5 if difficulty > 0
  163. 13 then: 6 if usedie + modify >= difficulty
  164. 6 result.success = true
  165. 6 output.push("成功")
  166. else: 7 else
  167. 7 output.push("失敗")
  168. end
  169. end
  170. 18 Result.new.tap do |r|
  171. 18 r.text = output.join(" > ")
  172. 18 then: 18 else: 0 if result
  173. 18 then: 13 else: 5 if difficulty > 0
  174. 13 r.condition = result.success?
  175. end
  176. 18 r.critical = result.critical?
  177. 18 r.fumble = result.fumble?
  178. end
  179. end
  180. end
  181. # 武器の両手持ちダメージ
  182. 1 def twohands_damage_roll(command)
  183. 6 m = /^2H(\d+)D(\d+)([+-]\d+)?/.match(command)
  184. 6 else: 6 then: 0 unless m
  185. return nil
  186. end
  187. 6 dice_count = m[1].to_i
  188. 6 dice_number = m[2].to_i
  189. 6 modify = m[3].to_i
  190. 6 mod_str = number_with_sign_from_int(modify)
  191. 6 output = ["(2H#{dice_count}D#{dice_number}#{mod_str})"]
  192. 6 dice = @randomizer.roll_barabara(dice_count, dice_number)
  193. 6 roll_dice = "[" + dice.join(",") + "]"
  194. 6 output.push("#{roll_dice}#{mod_str}")
  195. 6 ex_dice = []
  196. 6 new_dice = []
  197. 6 sum_dice = 0
  198. 6 dice.each do |num|
  199. 18 then: 15 if num.to_i > 2
  200. 15 sum_dice += num.to_i
  201. 15 ex_dice.push(num)
  202. else: 3 else
  203. 3 one_die = @randomizer.roll_once(dice_number)
  204. 3 sum_dice += one_die.to_i
  205. 3 new_dice.push(one_die)
  206. end
  207. end
  208. 6 else: 3 then: 3 unless new_dice.empty?
  209. 3 output.push("[" + ex_dice.join(",") + "][" + new_dice.join(",") + "]#{mod_str}")
  210. end
  211. 6 output.push((sum_dice + modify).to_s)
  212. 6 Result.new.tap do |r|
  213. 6 r.text = output.join(" > ")
  214. end
  215. end
  216. end
  217. end
  218. end

lib/bcdice/game_system/EarthDawn.rb

94.26% lines covered

78.85% branches covered

122 relevant lines. 115 lines covered and 7 lines missed.
52 total branches, 41 branches covered and 11 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class EarthDawn < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'EarthDawn'
  7. # ゲームシステム名
  8. 1 NAME = 'アースドーン'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ああすとおん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ステップダイス (xEn+k)
  14. ステップx、目標値n(省略可能)、カルマダイスk(D2-D20)でステップダイスをロールします。
  15. 振り足しも自動。
  16. 例)9E 10E8 10E+D12
  17. INFO_MESSAGE_TEXT
  18. 1 register_prefix('\d+e')
  19. 1 def initialize(command)
  20. 142 super(command)
  21. 142 @sort_add_dice = true
  22. end
  23. 1 def eval_game_system_specific_command(command)
  24. 72 return ed_step(command)
  25. end
  26. # アースドーンステップ表
  27. 1 def ed_step(str)
  28. 72 output = getStepResult(str)
  29. 72 return output
  30. end
  31. 1 def getStepResult(str)
  32. 72 else: 72 then: 0 return nil unless /(\d+)E(\d+)?(\+)?(\d+)?(d\d+)?/i =~ str
  33. 72 stepTotal = 0
  34. 72 @isFailed = true
  35. 72 step = Regexp.last_match(1).to_i # ステップ
  36. 72 targetNumber = 0 # 目標値
  37. 72 hasKarmaDice = false # カルマダイスの有無
  38. 72 karmaDiceCount = 0 # カルマダイスの個数又は修正
  39. 72 karmaDiceType = 0 # カルマダイスの種類
  40. # 空値があった時の為のばんぺいくんRX
  41. 72 then: 0 else: 72 if step > 40
  42. step = 40
  43. end
  44. 72 then: 71 else: 1 if Regexp.last_match(2)
  45. 71 targetNumber = Regexp.last_match(2).to_i
  46. 71 then: 0 else: 71 targetNumber = 42 if targetNumber > 43
  47. end
  48. 72 then: 60 else: 12 hasKarmaDice = Regexp.last_match(3).to_i if Regexp.last_match(3)
  49. 72 then: 60 else: 12 karmaDiceCount = Regexp.last_match(4).to_i if Regexp.last_match(4)
  50. 72 then: 0 else: 72 karmaDiceType = Regexp.last_match(5) if Regexp.last_match(5)
  51. 72 then: 0 else: 72 return nil if targetNumber < 0
  52. 72 stable = getStepTable()
  53. 72 nmod = stable[0][step - 1]
  54. 72 d20step = stable[1][step - 1]
  55. 72 d12step = stable[2][step - 1]
  56. 72 d10step = stable[3][step - 1]
  57. 72 d8step = stable[4][step - 1]
  58. 72 d6step = stable[5][step - 1]
  59. 72 d4step = stable[6][step - 1]
  60. 72 then: 60 else: 12 if hasKarmaDice
  61. 60 case karmaDiceType
  62. when: 0 when /d20/i
  63. d20step += karmaDiceCount
  64. when: 0 when /d12/i
  65. d12step += karmaDiceCount
  66. when: 0 when /d10/i
  67. d10step += karmaDiceCount
  68. when: 0 when /d8/i
  69. d8step += karmaDiceCount
  70. when: 0 when /d6/i
  71. d6step += karmaDiceCount
  72. when: 0 when /d4/i
  73. d4step += karmaDiceCount
  74. else: 60 else
  75. 60 nmod += karmaDiceCount
  76. end
  77. end
  78. 72 @string = ""
  79. 72 debug('d20step, d12step, d10step, d8step, d6step, d4step', d20step, d12step, d10step, d8step, d6step, d4step)
  80. 72 stepTotal += rollStep(20, d20step)
  81. 72 stepTotal += rollStep(12, d12step)
  82. 72 stepTotal += rollStep(10, d10step)
  83. 72 stepTotal += rollStep(8, d8step)
  84. 72 stepTotal += rollStep(6, d6step)
  85. 72 stepTotal += rollStep(4, d4step)
  86. 72 then: 60 else: 12 if nmod > 0 # 修正分の適用
  87. 60 @string += "+"
  88. end
  89. 72 then: 60 else: 12 if nmod != 0
  90. 60 @string += nmod.to_s
  91. 60 stepTotal += nmod
  92. end
  93. # ステップ判定終了
  94. 72 @string += " > #{stepTotal}"
  95. 72 output = "ステップ#{step} > #{@string}"
  96. 72 then: 2 else: 70 return output if targetNumber == 0
  97. # 結果判定
  98. 70 @string += ' > '
  99. 70 excelentSuccessNumber = stable[7][targetNumber - 1]
  100. 70 superSuccessNumber = stable[8][targetNumber - 1]
  101. 70 goodSuccessNumber = stable[9][targetNumber - 1]
  102. 70 failedNumber = stable[11][targetNumber - 1]
  103. 70 then: 1 if @isFailed
  104. 1 else: 69 @string += '自動失敗'
  105. 69 then: 20 elsif stepTotal >= excelentSuccessNumber
  106. 20 else: 49 @string += '最良成功'
  107. 49 then: 10 elsif stepTotal >= superSuccessNumber
  108. 10 else: 39 @string += '優成功'
  109. 39 then: 15 elsif stepTotal >= goodSuccessNumber
  110. 15 else: 24 @string += '良成功'
  111. 24 then: 13 elsif stepTotal >= targetNumber
  112. 13 else: 11 @string += '成功'
  113. 11 then: 1 elsif stepTotal < failedNumber
  114. 1 @string += '大失敗'
  115. else: 10 else
  116. 10 @string += '失敗'
  117. end
  118. 70 output = "ステップ#{step}>=#{targetNumber} > #{@string}"
  119. 70 return output
  120. end
  121. 1 def getStepTable
  122. # 表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 34x 3x 4x 5x 6x 7x 8x 9x10x11x12x13x
  123. 72 mod = [-2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,]
  124. 72 d20 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,]
  125. 72 d12 = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1,]
  126. 72 d10 = [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 2, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 3, 2, 1, 1, 1, 2, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 2, 1,]
  127. 72 d8 = [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0,]
  128. 72 d6 = [0, 0, 0, 1, 0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 2, 1, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 2, 1, 1, 0, 0, 0,]
  129. 72 d4 = [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,]
  130. 72 exsuc = [6, 8, 10, 12, 14, 17, 19, 20, 22, 24, 25, 27, 29, 32, 33, 35, 37, 38, 39, 41, 42, 44, 45, 47, 48, 49, 51, 52, 54, 55, 56, 58, 59, 60, 62, 64, 65, 67, 68, 70, 71, 72,]
  131. 72 ssuc = [4, 6, 8, 10, 11, 13, 15, 16, 18, 19, 21, 22, 24, 26, 27, 29, 30, 32, 33, 34, 35, 37, 38, 40, 41, 42, 43, 45, 46, 47, 48, 49, 51, 52, 53, 55, 56, 58, 59, 60, 61, 62,]
  132. 72 gsuc = [2, 4, 6, 7, 9, 10, 12, 13, 14, 15, 17, 18, 20, 21, 22, 24, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35, 36, 38, 39, 40, 41, 42, 43, 45, 46, 47, 48, 50, 51, 52, 53, 54,]
  133. 72 nsuc = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,]
  134. 72 fsuc = [0, 1, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9, 10, 11, 12, 13, 13, 14, 15, 16, 17, 18, 18, 18, 20, 21, 22, 23, 23, 24, 25, 26, 26, 27, 28, 29, 30,]
  135. 72 stable = [mod, d20, d12, d10, d8, d6, d4, exsuc, ssuc, gsuc, nsuc, fsuc]
  136. 72 return stable
  137. end
  138. # 41以上のステップの為の配列です。
  139. # 以下のようなルールでダイスを増やしています。より正しいステップ計算法をご存知の方は、
  140. # どうぞそちらに合せて調整して下さい。
  141. #  基本: 2d20+d10+d8
  142. #  これを仮にステップ34xとしています。
  143. #  一般式としては、ステップxxのダイスは、
  144. #   ステップ34xのダイス
  145. # + [(xx-45)/11]d20
  146. # + ステップ[(xx-34)を11で割った余り+3]のダイス
  147. 1 def rollStep(diceType, diceCount)
  148. 432 debug('rollStep diceType, diceCount, @string', diceType, diceCount, @string)
  149. 432 stepTotal = 0
  150. 432 else: 195 then: 237 return stepTotal unless diceCount > 0
  151. # diceぶんのステップ判定
  152. 195 else: 72 then: 123 @string += "+" unless @string.empty?
  153. 195 @string += "#{diceCount}d#{diceType}["
  154. 195 debug('rollStep @string', @string)
  155. 195 diceCount.times do |i|
  156. 247 dice_now = @randomizer.roll_once(diceType)
  157. 247 then: 229 else: 18 if dice_now != 1
  158. 229 @isFailed = false
  159. end
  160. 247 dice_in = dice_now
  161. 247 body: 43 while dice_now == diceType
  162. 43 dice_now = @randomizer.roll_once(diceType)
  163. 43 dice_in += dice_now
  164. end
  165. 247 stepTotal += dice_in
  166. 247 then: 52 else: 195 @string += ',' if i != 0
  167. 247 @string += dice_in.to_s
  168. end
  169. 195 @string += "]"
  170. 195 return stepTotal
  171. end
  172. end
  173. end
  174. end

lib/bcdice/game_system/EarthDawn3.rb

100.0% lines covered

89.19% branches covered

111 relevant lines. 111 lines covered and 0 lines missed.
37 total branches, 33 branches covered and 4 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/EarthDawn'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class EarthDawn3 < EarthDawn
  6. # ゲームシステムの識別子
  7. 1 ID = 'EarthDawn3'
  8. # ゲームシステム名
  9. 1 NAME = 'アースドーン3版'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'ああすとおん3'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ステップダイス (xEn+k)
  15. ステップx、目標値n(省略可能)、カルマダイスk(D2~D20)でステップダイスをロールします。
  16. 振り足しも自動。
  17. 例)ステップ10:10E
  18.   ステップ10、目標値8:10E8
  19.   ステップ12、目標値8、カルマダイスD12:10E8+1D6
  20. INFO_MESSAGE_TEXT
  21. 1 register_prefix('\d+e')
  22. 1 def initialize(command)
  23. 35 super(command)
  24. 35 @sort_add_dice = true
  25. end
  26. 1 def eval_game_system_specific_command(command)
  27. 35 return ed_step(command)
  28. end
  29. # アースドーンステップ表
  30. 1 def ed_step(str)
  31. 35 output = getStepResult(str)
  32. 35 return output
  33. end
  34. 1 def getStepResult(str)
  35. 35 else: 35 then: 0 return nil unless /^(\d+)E(\d+)?(\+(\d*)D(\d+))?(\+\d)?/i =~ str
  36. 35 stepTotal = 0
  37. 35 @isFailed = true
  38. 35 step = Regexp.last_match(1).to_i # ステップ
  39. 35 targetNumber = [Regexp.last_match(2).to_i, 20].min # 目標値
  40. 35 hasKarmaDice = !Regexp.last_match(3).nil? # カルマダイスの有無
  41. 35 karmaDiceCount = [1, Regexp.last_match(4).to_i].max # カルマダイスの個数
  42. 35 karmaDiceType = Regexp.last_match(5).to_i # カルマダイスの種類
  43. 35 diceModify = Regexp.last_match(6).to_i
  44. 35 karmaDiceInfo = Hash.new(0)
  45. 35 then: 4 else: 31 if hasKarmaDice
  46. 4 karmaDiceInfo[karmaDiceType] = karmaDiceCount
  47. end
  48. 35 then: 0 else: 35 return nil if targetNumber < 0
  49. 35 stepInfo = getStepInfo(step)
  50. 35 debug('stepInfo', stepInfo)
  51. 35 @string = ""
  52. 35 diceTypes = [20, 12, 10, 8, 6, 4]
  53. 35 diceTypes.each do |type|
  54. 210 stepTotal += rollStep(type, stepInfo.shift)
  55. end
  56. 35 modify = stepInfo.shift
  57. 35 karmaDiceInfo.each do |diceType, diceCount|
  58. 4 stepTotal += rollStep(diceType, diceCount)
  59. end
  60. 35 @string += (getModifyText(modify) + getModifyText(diceModify))
  61. 35 stepTotal += (modify + diceModify)
  62. # ステップ判定終了
  63. 35 @string += " > #{stepTotal}"
  64. 35 output = "ステップ#{step} > #{@string}"
  65. 35 then: 2 else: 33 return output if targetNumber == 0
  66. # 結果判定
  67. 33 @string += ' > ' + getSuccess(targetNumber, stepTotal)
  68. 33 output = "ステップ#{step}>=#{targetNumber} > #{@string}"
  69. 33 return output
  70. end
  71. 1 def getModifyText(modify)
  72. 70 @string = ""
  73. 70 then: 68 else: 2 return @string if modify == 0
  74. 2 then: 2 else: 0 @string += "+" if modify > 0
  75. 2 @string += modify.to_s
  76. 2 return @string
  77. end
  78. 1 def getBaseStepTable
  79. stepTable =
  80. [
  81. # dice
  82. # D20 D12 D10 D8 D6 D4 mod
  83. 35 [1, [0, 0, 0, 0, 1, 0, -3]],
  84. [2, [0, 0, 0, 0, 1, 0, -2]],
  85. [3, [0, 0, 0, 0, 1, 0, -1]],
  86. [4, [0, 0, 0, 0, 1, 0, 0]],
  87. [5, [0, 0, 0, 1, 0, 0, 0]],
  88. [6, [0, 0, 1, 0, 0, 0, 0]],
  89. [7, [0, 1, 0, 0, 0, 0, 0]],
  90. ]
  91. 35 return stepTable
  92. end
  93. 1 def getStepInfo(step)
  94. 35 baseStepTable = getBaseStepTable
  95. 35 baseMaxStep = baseStepTable.last.first
  96. 35 then: 4 else: 31 if step <= baseMaxStep
  97. 4 return get_table_by_number(step, baseStepTable)
  98. end
  99. 31 baseStepInfo = [0, 1, 0, 0, 0, 0, 0]
  100. 31 overStep = step - baseMaxStep - 1
  101. stepRythm =
  102. [
  103. # dice
  104. # D20 D12 D10 D8 D6 D4 mod
  105. 31 [0, 0, 0, 0, 2, 0, 0],
  106. [0, 0, 0, 1, 1, 0, 0],
  107. [0, 0, 0, 2, 0, 0, 0],
  108. [0, 0, 1, 1, 0, 0, 0],
  109. [0, 0, 2, 0, 0, 0, 0],
  110. [0, 1, 1, 0, 0, 0, 0],
  111. [0, 2, 0, 0, 0, 0, 0],
  112. ]
  113. 31 result = [0, 0, 0, 0, 0, 0, 0]
  114. 31 loopCount = (overStep / stepRythm.size)
  115. 31 loopCount.times do
  116. 13 addStepToResult(result, baseStepInfo)
  117. end
  118. 31 index = (overStep % stepRythm.size)
  119. 31 restStepInfo = stepRythm[index]
  120. 31 addStepToResult(result, restStepInfo)
  121. 31 return result
  122. end
  123. 1 def addStepToResult(result, step)
  124. 44 result.size.times do |i|
  125. 308 result[i] += step[i]
  126. end
  127. 44 return result
  128. end
  129. 1 def getSuccess(targetNumber, stepTotal)
  130. 33 then: 3 else: 30 return '自動失敗' if @isFailed
  131. 30 successTable = getSuccessTable
  132. 30 successInfo = get_table_by_number(targetNumber, successTable)
  133. 30 pathetic, poor, average, good, excelent, extraordinary = successInfo
  134. 30 then: 10 else: 20 return 'Extraordinary(極上)' if stepTotal >= extraordinary
  135. 20 then: 3 else: 17 return 'Excelent(最高)' if stepTotal >= excelent
  136. 17 then: 5 else: 12 return 'Good(上出来)' if stepTotal >= good
  137. 12 then: 2 else: 10 return 'Average(そこそこ)' if stepTotal >= average
  138. 10 then: 8 else: 2 return 'Poor(お粗末)' if stepTotal >= poor
  139. 2 then: 2 else: 0 return 'Pathetic(惨め)' if stepTotal >= pathetic
  140. end
  141. 1 def getSuccessTable
  142. successTable =
  143. [
  144. # Pathetic Poor Average Good Excellent Extraordinary
  145. 30 [2, [0, 1, 2, 5, 7, 9]],
  146. [3, [0, 1, 3, 6, 8, 10]],
  147. [4, [0, 1, 4, 7, 10, 12]],
  148. [5, [1, 2, 5, 8, 11, 14]],
  149. [6, [1, 2, 6, 9, 13, 17]],
  150. [7, [1, 3, 7, 11, 15, 19]],
  151. [8, [1, 4, 8, 13, 16, 20]],
  152. [9, [1, 5, 9, 15, 18, 22]],
  153. [10, [1, 6, 10, 16, 20, 24]],
  154. [11, [1, 6, 11, 17, 21, 25]],
  155. [12, [1, 7, 12, 18, 23, 27]],
  156. [13, [1, 7, 13, 20, 25, 29]],
  157. [14, [1, 8, 14, 21, 26, 31]],
  158. [15, [1, 9, 15, 23, 27, 31]],
  159. [16, [1, 10, 16, 24, 28, 33]],
  160. [17, [1, 11, 17, 25, 30, 34]],
  161. [18, [1, 12, 18, 26, 31, 36]],
  162. [19, [1, 12, 19, 28, 33, 37]],
  163. [20, [1, 13, 20, 29, 34, 39]],
  164. [21, [1, 14, 21, 30, 36, 41]],
  165. [22, [1, 15, 22, 31, 37, 42]],
  166. [23, [1, 16, 23, 33, 38, 43]],
  167. [24, [1, 16, 24, 34, 39, 44]],
  168. [25, [1, 17, 25, 35, 41, 46]],
  169. [26, [1, 18, 26, 36, 42, 47]],
  170. [27, [1, 19, 27, 37, 43, 49]],
  171. [28, [1, 19, 28, 39, 45, 50]],
  172. [29, [1, 21, 29, 40, 46, 51]],
  173. [30, [1, 21, 30, 41, 47, 53]],
  174. [31, [1, 22, 31, 42, 48, 54]],
  175. [32, [1, 23, 32, 43, 49, 55]],
  176. [33, [1, 24, 33, 45, 51, 57]],
  177. [34, [1, 24, 34, 46, 52, 58]],
  178. [35, [1, 25, 35, 47, 53, 60]],
  179. [36, [1, 26, 36, 48, 54, 60]],
  180. [37, [1, 27, 37, 49, 56, 62]],
  181. [38, [1, 28, 38, 51, 57, 63]],
  182. [39, [1, 29, 39, 52, 58, 64]],
  183. [40, [1, 30, 40, 53, 59, 66]],
  184. ]
  185. 30 return successTable
  186. end
  187. 1 def rollStep(diceType, diceCount)
  188. 214 debug('rollStep diceType, diceCount, @string', diceType, diceCount, @string)
  189. 214 stepTotal = 0
  190. 214 else: 46 then: 168 return stepTotal unless diceCount > 0
  191. # diceぶんのステップ判定
  192. 46 else: 35 then: 11 @string += "+" unless @string.empty?
  193. 46 @string += "#{diceCount}d#{diceType}["
  194. 46 debug('rollStep @string', @string)
  195. 46 diceCount.times do |i|
  196. 83 dice_now = @randomizer.roll_once(diceType)
  197. 83 then: 61 else: 22 if dice_now != 1
  198. 61 @isFailed = false
  199. end
  200. 83 dice_in = dice_now
  201. 83 body: 2 while dice_now == diceType
  202. 2 dice_now = @randomizer.roll_once(diceType)
  203. 2 dice_in += dice_now
  204. end
  205. 83 stepTotal += dice_in
  206. 83 then: 37 else: 46 @string += ',' if i != 0
  207. 83 @string += dice_in.to_s
  208. end
  209. 46 @string += "]"
  210. 46 return stepTotal
  211. end
  212. end
  213. end
  214. end

lib/bcdice/game_system/EarthDawn4.rb

100.0% lines covered

85.0% branches covered

129 relevant lines. 129 lines covered and 0 lines missed.
40 total branches, 34 branches covered and 6 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/EarthDawn'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class EarthDawn4 < EarthDawn
  6. # ゲームシステムの識別子
  7. 1 ID = 'EarthDawn4'
  8. # ゲームシステム名
  9. 1 NAME = 'アースドーン4版'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'ああすとおん4'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ステップダイス (xEnK)
  15. ステップx、目標値n(省略可能)でステップダイスをロール。
  16. カルマダイス使用時は末尾にKを追加(省略可能)
  17. 例)ステップ10:10E
  18.   ステップ10、目標値8:10E8
  19.   ステップ10、目標値8、カルマダイス:10E8K
  20. INFO_MESSAGE_TEXT
  21. 1 register_prefix('\d+e')
  22. 1 def initialize(command)
  23. 35 super(command)
  24. 35 @sort_add_dice = true
  25. 35 @calcText = ''
  26. end
  27. 1 def eval_game_system_specific_command(command)
  28. 35 return ed_step(command)
  29. end
  30. # アースドーンステップ表
  31. 1 def ed_step(str)
  32. 35 output = getStepResult(str)
  33. 35 return output
  34. end
  35. 1 def getStepResult(str)
  36. 35 stepText, calcText, stepTotal, targetNumber = getStepResultInfos(str)
  37. 35 then: 0 else: 35 return nil if stepText.nil?
  38. 35 then: 5 else: 30 if targetNumber == 0
  39. 5 output = "#{stepText} > #{calcText} > #{stepTotal}"
  40. 5 return output
  41. end
  42. # 結果判定
  43. 30 successText = getSuccess(targetNumber, stepTotal)
  44. 30 output = "#{stepText}>=#{targetNumber} > #{calcText} > #{stepTotal} > #{successText}"
  45. 30 return output
  46. end
  47. 1 def getStepResultInfos(str)
  48. 35 steps = []
  49. 35 calcs = []
  50. 35 totals = []
  51. 35 target = 0
  52. 35 while !str.nil? && !str.empty?
  53. body: 37
  54. 37 debug("=====>!! str", str)
  55. 37 step, calc, total, value, nextText = getStepResultInfo(str)
  56. 37 debug("=====> step", step)
  57. 37 then: 0 else: 37 return nil if step.nil?
  58. 37 steps << step
  59. 37 calcs << calc
  60. 37 totals << total
  61. 37 else: 7 then: 30 target = value unless value == 0
  62. 37 debug("=====> nextText", nextText)
  63. 37 then: 0 else: 37 break if nextText == str
  64. 37 str = nextText
  65. end
  66. 35 stepText = steps.join("+")
  67. 35 calcText = calcs.join(")+(")
  68. 37 stepTotal = totals.inject { |sum, i| sum + i }
  69. 35 then: 2 else: 33 calcText = "(" + calcText + ")" if calcs.size > 1
  70. 35 then: 2 else: 33 calcText += " > (#{totals.join('+')})" if totals.size > 1
  71. 35 return stepText, calcText, stepTotal, target
  72. end
  73. 1 def getStepResultInfo(str)
  74. 37 else: 37 then: 0 return nil unless /^(\d+)E(\d+)?(K)?(\+\d+$)?(\+(.*))?/i =~ str
  75. 37 stepTotal = 0
  76. 37 @isFailed = true
  77. 37 step = Regexp.last_match(1).to_i # ステップ
  78. 37 targetNumber = Regexp.last_match(2).to_i # 目標値
  79. 37 then: 0 else: 37 return nil if targetNumber < 0
  80. 37 hasKarmaDice = !Regexp.last_match(3).nil? # カルマダイスの有無
  81. 37 diceModify = Regexp.last_match(4).to_i
  82. 37 nextText = Regexp.last_match(6)
  83. 37 stepInfo = getStepInfo(step)
  84. 37 debug('stepInfo', stepInfo)
  85. 37 @calcText = ""
  86. 37 diceTypes = [20, 12, 10, 8, 6, 4]
  87. 37 diceTypes.each do |type|
  88. 222 stepTotal += rollStep(type, stepInfo.shift)
  89. end
  90. 37 modify = stepInfo.shift
  91. 37 then: 6 else: 31 stepTotal += rollStep(6, 1) if hasKarmaDice
  92. 37 @calcText += (getModifyText(modify) + getModifyText(diceModify))
  93. 37 stepTotal += (modify + diceModify)
  94. 37 stepText = "ステップ#{step}"
  95. 37 return stepText, @calcText, stepTotal, targetNumber, nextText
  96. end
  97. 1 def getModifyText(modify)
  98. 74 string = ""
  99. 74 then: 71 else: 3 return string if modify == 0
  100. 3 then: 3 else: 0 string += "+" if modify > 0
  101. 3 string += modify.to_s
  102. 3 return string
  103. end
  104. 1 def getBaseStepTable
  105. stepTable =
  106. [
  107. # dice
  108. # D20 D12 D10 D8 D6 D4 mod
  109. 37 [1, [0, 0, 0, 0, 0, 1, -2]],
  110. [2, [0, 0, 0, 0, 0, 1, -1]],
  111. [3, [0, 0, 0, 0, 0, 1, 0]],
  112. [4, [0, 0, 0, 0, 1, 0, 0]],
  113. [5, [0, 0, 0, 1, 0, 0, 0]],
  114. [6, [0, 0, 1, 0, 0, 0, 0]],
  115. [7, [0, 1, 0, 0, 0, 0, 0]],
  116. ]
  117. 37 return stepTable
  118. end
  119. 1 def getStepInfo(step)
  120. 37 baseStepTable = getBaseStepTable
  121. 37 baseMaxStep = baseStepTable.last.first
  122. 37 then: 9 else: 28 if step <= baseMaxStep
  123. 9 return get_table_by_number(step, baseStepTable)
  124. end
  125. # dice
  126. # D20 D12 D10 D8 D6 D4 mod
  127. 28 overBounusStep = [1, 0, 0, 0, 0, 0, 0]
  128. 28 overStep = step - baseMaxStep - 1
  129. stepRythm =
  130. [
  131. # dice
  132. # D20 D12 D10 D8 D6 D4 mod
  133. 28 [0, 0, 0, 0, 2, 0, 0],
  134. [0, 0, 0, 1, 1, 0, 0],
  135. [0, 0, 0, 2, 0, 0, 0],
  136. [0, 0, 1, 1, 0, 0, 0],
  137. [0, 0, 2, 0, 0, 0, 0],
  138. [0, 1, 1, 0, 0, 0, 0],
  139. [0, 2, 0, 0, 0, 0, 0],
  140. [0, 1, 0, 0, 2, 0, 0],
  141. [0, 1, 0, 1, 1, 0, 0],
  142. [0, 1, 0, 2, 0, 0, 0],
  143. [0, 1, 1, 1, 0, 0, 0],
  144. ]
  145. # [ 1, 0, 0, 0, 2, 0, 0],
  146. 28 result = [0, 0, 0, 0, 0, 0, 0]
  147. 28 loopCount = (overStep / stepRythm.size)
  148. 28 loopCount.times do
  149. 10 addStepToResult(result, overBounusStep)
  150. end
  151. 28 index = (overStep % stepRythm.size)
  152. 28 restStepInfo = stepRythm[index]
  153. 28 addStepToResult(result, restStepInfo)
  154. 28 return result
  155. end
  156. 1 def addStepToResult(result, step)
  157. 38 result.size.times do |i|
  158. 266 result[i] += step[i]
  159. end
  160. 38 return result
  161. end
  162. 1 def getSuccess(targetNumber, stepTotal)
  163. 30 then: 3 else: 27 return '自動失敗' if @isFailed
  164. 27 diff = stepTotal - targetNumber
  165. 27 debug("diff", diff)
  166. 27 then: 3 else: 24 if diff < 0
  167. 3 return "失敗"
  168. end
  169. 24 level = (diff / 5) + 1
  170. 24 return "成功 レベル:#{level}"
  171. end
  172. 1 def rollStep(diceType, diceCount)
  173. 228 debug('rollStep diceType, diceCount, @calcText', diceType, diceCount, @calcText)
  174. 228 stepTotal = 0
  175. 228 else: 65 then: 163 return stepTotal unless diceCount > 0
  176. # diceぶんのステップ判定
  177. 65 else: 37 then: 28 @calcText += "+" unless @calcText.empty?
  178. 65 @calcText += "#{diceCount}d#{diceType}["
  179. 65 debug('rollStep string', @calcText)
  180. 65 diceCount.times do |i|
  181. 88 dice_now = @randomizer.roll_once(diceType)
  182. 88 then: 75 else: 13 if dice_now != 1
  183. 75 @isFailed = false
  184. end
  185. 88 dice_in = dice_now
  186. 88 body: 6 while dice_now == diceType
  187. 6 dice_now = @randomizer.roll_once(diceType)
  188. 6 dice_in += dice_now
  189. end
  190. 88 stepTotal += dice_in
  191. 88 then: 23 else: 65 @calcText += ',' if i != 0
  192. 88 @calcText += dice_in.to_s
  193. end
  194. 65 @calcText += "]"
  195. 65 return stepTotal
  196. end
  197. end
  198. end
  199. end

lib/bcdice/game_system/EclipsePhase.rb

100.0% lines covered

94.44% branches covered

26 relevant lines. 26 lines covered and 0 lines missed.
18 total branches, 17 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class EclipsePhase < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'EclipsePhase'
  7. # ゲームシステム名
  8. 1 NAME = 'エクリプス・フェイズ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'えくりふすふえいす'
  11. # ダイスボットの使い方
  12. HELP_MESSAGE =
  13. 1 '1D100<=m 方式の判定で成否、クリティカル・ファンブルを自動判定'
  14. 1 def result_1d100(total, _dice_total, cmp_op, target)
  15. 14 then: 1 else: 13 return nil if target == '?'
  16. 13 else: 13 then: 0 return nil unless cmp_op == :<=
  17. 13 dice_value = total % 100 # 出目00は100ではなく00とする
  18. 13 dice_ten_place = dice_value / 10
  19. 13 dice_one_place = dice_value % 10
  20. 13 then: 6 else: 7 if dice_ten_place == dice_one_place
  21. 6 then: 2 else: 4 return Result.fumble('決定的失敗') if dice_value == 99
  22. 4 then: 2 else: 2 return Result.critical('00 > 決定的成功') if dice_value == 0
  23. 2 then: 1 else: 1 return Result.critical('決定的成功') if total <= target
  24. 1 return Result.fumble('決定的失敗')
  25. end
  26. 7 diff_threshold = 30
  27. 7 then: 4 if total <= target
  28. 4 then: 3 if total >= diff_threshold
  29. 3 Result.success('エクセレント')
  30. else: 1 else
  31. 1 Result.success('成功')
  32. else: 3 end
  33. 3 then: 1 elsif (total - target) >= diff_threshold
  34. 1 Result.failure('シビア')
  35. else: 2 else
  36. 2 Result.failure('失敗')
  37. end
  38. end
  39. end
  40. end
  41. end

lib/bcdice/game_system/Elric.rb

95.45% lines covered

92.86% branches covered

22 relevant lines. 21 lines covered and 1 lines missed.
14 total branches, 13 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Elric < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Elric'
  7. # ゲームシステム名
  8. 1 NAME = 'エルリック!'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'えるりつく'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = "貫通、クリティカル、ファンブルの自動判定を行います。\n"
  13. # ゲーム別成功度判定(1d100)
  14. 1 def result_1d100(total, _dice_total, cmp_op, target)
  15. 12 else: 11 then: 1 return nil unless cmp_op == :<=
  16. 11 then: 2 if total <= 1
  17. 2 else: 9 Result.critical("貫通") # 1は常に貫通
  18. 9 then: 2 elsif total >= 100
  19. 2 else: 7 Result.fumble("致命的失敗") # 100は常に致命的失敗
  20. 7 then: 0 elsif target == '?'
  21. else: 7 Result.nothing
  22. 7 then: 2 elsif total <= (target / 5.0).ceil
  23. 2 else: 5 Result.critical("決定的成功")
  24. 5 then: 2 elsif total <= target
  25. 2 else: 3 Result.success("成功")
  26. 3 then: 1 elsif (total >= 99) && (target < 100)
  27. 1 Result.fumble("致命的失敗")
  28. else: 2 else
  29. 2 Result.failure("失敗")
  30. end
  31. end
  32. end
  33. end
  34. end

lib/bcdice/game_system/Elysion.rb

99.65% lines covered

89.04% branches covered

285 relevant lines. 284 lines covered and 1 lines missed.
73 total branches, 65 branches covered and 8 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Elysion < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Elysion'
  7. # ゲームシステム名
  8. 1 NAME = 'エリュシオン'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'えりゆしおん'
  11. # ダイスボットの使い方
  12. #
  13. # 教室 R:classRoom/購買 S:Shop/部室 B:Box/生徒会室 C:Council/学生寮 D:Dormitory/図書館 I:lIbrary/屋上 F:rooF/
  14. #  研究室 L:Labo/プール P:Pool/中庭 N:iNner/商店街 A:Avenue/廃墟 V:deVastation/ゲート G:Gate
  15. # 温泉 H:Hotsprings/修学旅行 T:School trip/お祭り室 E:festival/潜入調査 U:Infiltration study/
  16. 1 HELP_MESSAGE = <<~MESSAGETEXT
  17. ・判定(ELn+m)
  18.  能力値 n 、既存の達成値 m(アシストの場合)
  19. 例)EL3 :能力値3で判定。
  20.   EL5+10:能力値5、達成値が10の状態にアシストで判定。
  21. ・ファンブル表 FT
  22. ・戦場表 BFT
  23. ・致命傷表 FWT
  24. ・陰謀表 GIT
  25. ・新初期アイテム決定表 NA
  26. ・授業ハプニング表 JH
  27. ・日常遭遇表 NJ1~NJ11/ボスキャラクター遭遇表 BS1~BS11
  28. ファーストオーディション
  29. ・ユニット名決定表1A UT1/ユニット名決定表2A UT3
  30. ・ユニット名決定表1B UT2/ユニット名決定表2B UT4
  31. ・音楽ジャンル決定表A OJ1/・音楽ジャンル決定表B OJ2
  32. ライトオブカオス
  33. ・ニュートラル表 NT/・釣り人表 IT
  34. ・ロウ表 HT/・カオス表 KT
  35. ・休憩表(〜BT)
  36. 教室 RBT/購買 SBT/部室 BBT/生徒会室 CBT/学生寮 DBT/図書館 IBT/屋上 FBT/研究室 LBT/プール PBT/中庭 NBT/商店街 ABT/廃墟 VBT/ゲート GBT/温泉 HBT/修学旅行 TBT/お祭り室 EBT/潜入調査 UBT
  37. ・ランダムNPC表(〜RT)
  38.  学生生活関連NPC表 SRT/その他NPC表 ORT/学生図鑑 下級生表 DRT/学生図鑑 上級生表 URT
  39. ・デート表(DATE)/友達デート表(FDATE)/片思いデート表(ODATE)/真夜中デート表(MDATE)
  40. デート表のためにD6を振ります。
  41. DATE14 のようにコマンドの後に数値を入れると、その項目を参照します。
  42. ・デート表(DATE[PC名1,PC名2])
  43.  1コマンドでデート判定を行い、デート表の結果を表示します。
  44. ・D66ダイスあり
  45. MESSAGETEXT
  46. 1 def initialize(command)
  47. 86 super(command)
  48. 86 @d66_sort_type = D66SortType::ASC
  49. 86 @enabled_upcase_input = false
  50. end
  51. 1 def eval_game_system_specific_command(command)
  52. 84 debug('eval_game_system_specific_command command', command)
  53. 84 result = ''
  54. 84 case command
  55. when: 12 when /^EL(\d*)(\+\d+)?/i
  56. 12 base = Regexp.last_match(1)
  57. 12 modify = Regexp.last_match(2)
  58. 12 result = check(base, modify)
  59. when: 13 when /^(F|O|M)?DATE\[(.*),(.*)\]/i
  60. 13 type = Regexp.last_match(1)
  61. 13 pc1 = Regexp.last_match(2)
  62. 13 pc2 = Regexp.last_match(3)
  63. 13 result = getDateBothResult(type, pc1, pc2)
  64. when: 10 when /^(F|O|M)?DATE(\d\d)(\[(.*),(.*)\])?/i
  65. 10 type = Regexp.last_match(1)
  66. 10 number = Regexp.last_match(2).to_i
  67. 10 pc1 = Regexp.last_match(4)
  68. 10 pc2 = Regexp.last_match(5)
  69. 10 result = getDateResult(type, number, pc1, pc2)
  70. when: 5 when /^(F|O|M)?DATE/i
  71. 5 result = getDateValue
  72. else: 44 else
  73. 44 result = checkAnyCommand(command)
  74. 44 then: 17 else: 27 return roll_tables(command, TABLES) if result.empty?
  75. end
  76. 67 then: 12 else: 55 return result if result.instance_of?(Result)
  77. 55 then: 0 else: 55 return '' if result.empty?
  78. 55 return "#{command} > #{result}"
  79. end
  80. 1 def checkAnyCommand(command)
  81. result =
  82. 44 case command.upcase
  83. when: 1 when 'RBT'
  84. 1 getClassRoomBreakTable
  85. when: 1 when 'SBT'
  86. 1 getSchoolStoreBrakeTable
  87. when: 1 when 'BBT'
  88. 1 getClubRoomBrakeTable
  89. when: 1 when 'CBT'
  90. 1 getStudentCouncilBrakeTable
  91. when: 1 when 'DBT'
  92. 1 getDormitoryBrakeTable
  93. when: 1 when 'IBT'
  94. 1 getLibraryBrakeTable
  95. when: 1 when 'FBT'
  96. 1 getRoofBrakeTable
  97. when: 1 when 'LBT'
  98. 1 getLaboratoryBrakeTable
  99. when: 1 when 'PBT'
  100. 1 getPoolBrakeTable
  101. when: 1 when 'NBT'
  102. 1 getInnerCourtBrakeTable
  103. when: 1 when 'ABT'
  104. 1 getShoppingAvenueBrakeTable
  105. when: 1 when 'VBT'
  106. 1 getDevastationBrakeTable
  107. when: 1 when 'GBT'
  108. 1 getGateBrakeTable
  109. when: 1 when 'BFT'
  110. 1 getBattleFieldTable
  111. when: 1 when 'FWT'
  112. 1 getFatalWoundsTable
  113. when: 1 when 'FT'
  114. 1 getFumbleTable
  115. when: 2 when 'SRT'
  116. 2 getRandomNpcSchoolLife
  117. when: 2 when 'ORT'
  118. 2 getRandomNpcOther
  119. when: 2 when 'DRT'
  120. 2 getRandomNpcDownClassmen
  121. when: 2 when 'URT'
  122. 2 getRandomNpcUpperClassmen
  123. when: 2 when /^NJ(\d+)$/i
  124. 2 level = Regexp.last_match(1).to_i
  125. 2 getUsuallyEncount(level)
  126. when: 1 when /^BS(\d+)$/i
  127. 1 level = Regexp.last_match(1).to_i
  128. 1 getBossEncount(level)
  129. else: 17 else
  130. 17 ''
  131. end
  132. 44 return result
  133. end
  134. 1 def check(base, modify)
  135. 12 base = getValue(base)
  136. 12 modify = getValue(modify)
  137. 12 dice1 = @randomizer.roll_once(6)
  138. 12 dice2 = @randomizer.roll_once(6)
  139. 12 diceTotal = dice1 + dice2
  140. 12 addTotal = base + modify
  141. 12 total = diceTotal + addTotal
  142. 12 result = Result.new
  143. 12 result.text = "EL"
  144. 12 else: 2 then: 10 result.text += base.to_s unless base.zero?
  145. 12 else: 8 then: 4 result.text += getValueString(modify) unless modify.zero?
  146. 12 result.text += " > "
  147. 12 result.text += "(2D6#{getValueString(base)}#{getValueString(modify)})"
  148. 12 result.text += " > #{diceTotal}[#{dice1},#{dice2}]#{getValueString(addTotal)} > #{total}"
  149. 12 then: 5 else: 7 if dice1 == dice2
  150. 5 getSpecialResult(dice1, total, result)
  151. 5 return result
  152. end
  153. 7 result = getCheckResult(total, result)
  154. 7 return result
  155. end
  156. 1 def getValue(string)
  157. 24 then: 8 else: 16 return 0 if string.nil?
  158. 16 return string.to_i
  159. end
  160. 1 def getValueString(value)
  161. 40 then: 29 else: 11 return "+#{value}" if value > 0
  162. 11 then: 0 else: 11 return "-#{value}" if value < 0
  163. 11 return ""
  164. end
  165. 1 def getCheckResult(total, result)
  166. 10 success = getSuccessRank(total)
  167. 10 then: 2 else: 8 if success == 0
  168. 2 result.failure = true
  169. 2 result.text += " > 失敗"
  170. 2 return result
  171. end
  172. 8 return getSuccessResult(success, result)
  173. end
  174. 1 def getSuccessResult(success, result)
  175. 9 result.success = true
  176. 9 result.text += " > 成功度#{success}"
  177. 9 then: 2 else: 7 if success >= SUCCESS_MAX
  178. 2 result.critical = true
  179. 2 result.text += " > 大成功 《アウル》2点獲得"
  180. end
  181. 9 return result
  182. end
  183. 1 SUCCESS_MAX = 5
  184. 1 def getSuccessRank(total)
  185. 10 success = ((total - 9) / 5.0).ceil
  186. 10 then: 0 else: 10 success = 0 if success < 0
  187. 10 then: 0 else: 10 success = SUCCESS_MAX if success > SUCCESS_MAX
  188. 10 return success
  189. end
  190. 1 def getSpecialResult(number, total, result)
  191. 5 debug("getSpecialResult", number)
  192. 5 then: 1 else: 4 if number == 6
  193. 1 return getCriticalResult(result)
  194. end
  195. 4 return getFambleResultText(number, total, result)
  196. end
  197. 1 def getCriticalResult(result)
  198. 1 getSuccessResult(SUCCESS_MAX, result)
  199. end
  200. 1 def getFambleResultText(number, total, result)
  201. 4 debug("getFambleResultText number", number)
  202. 4 then: 1 else: 3 if number == 1
  203. 1 result.fumble = true
  204. 1 result.failure = true
  205. 1 result.text += " > 大失敗"
  206. 1 return result
  207. end
  208. 3 result = getCheckResult(total, result)
  209. 3 result.text += " / (#{number - 1}回目のアシストなら)大失敗"
  210. 3 debug("getFambleResultText result", result)
  211. 3 return result
  212. end
  213. 1 def getDateBothResult(type, pc1, pc2)
  214. 13 dice1 = @randomizer.roll_once(6)
  215. 13 dice2 = @randomizer.roll_once(6)
  216. 13 result = "#{pc1}[#{dice1}],#{pc2}[#{dice2}] > "
  217. 13 number = dice1 * 10 + dice2
  218. 13 then: 1 else: 12 if dice1 > dice2
  219. 1 tmp = pc1
  220. 1 pc1 = pc2
  221. 1 pc2 = tmp
  222. 1 number = dice2 * 10 + dice1
  223. end
  224. 13 result += getDateResult(type, number, pc1, pc2)
  225. 13 return result
  226. end
  227. 1 def getDateResult(type, number, pc1, pc2)
  228. 23 name, table = getDateTableByType(type)
  229. 23 debug("getDateTable name", name)
  230. 23 text = get_table_by_number(number, table)
  231. 23 text = changePcName(text, '受け身キャラ', pc1)
  232. 23 text = changePcName(text, '攻め気キャラ', pc2)
  233. 23 return "#{name}表(#{number}) > #{text}"
  234. end
  235. 1 def getDateTableByType(type)
  236. 23 else: 0 case type
  237. when: 11 when nil
  238. 11 return getDateTable()
  239. when: 4 when /^F$/i
  240. 4 return getFrindDateTable()
  241. when: 4 when /^O$/i
  242. 4 return getOnewayDateTable()
  243. when: 4 when /^M$/i
  244. 4 return getMidnightDateTable()
  245. end
  246. return '', []
  247. end
  248. 1 def getDateTable()
  249. 11 name = 'デート'
  250. table = [
  251. 11 [11, "「こんなはずじゃなかったのにッ!」仲良くするつもりが、ひどい喧嘩になってしまう。この表の使用者のお互いに対する《感情値》が1点上昇し、属性が《敵意》になる。"],
  252. [12, "「あなたってサイテー!!」大きな誤解が生まれる。受け身キャラの攻め気キャラ以外に対する《感情値》がすべて0になり、その値のぶんだけ攻め気キャラに対する《感情値》が上昇し、その属性が《敵意》になる。"],
  253. [13, "「ねぇねぇ知ってる…?」せっかく二人きりなのに、他人の話で盛り上がる。この表の使用者は、PCの中からこの表の使用者以外のキャラクター一人を選び、そのキャラクターに対する《感情値》が1点上昇する。"],
  254. [14, "「そこもっとくわしく!」互いの好きなものについて語り合う。受け身キャラは、攻め気キャラの「好きなもの」一つを選ぶ。受け身キャラは、自分の「好きなもの」一つをそれに変更したうえで、攻め気キャラへの《感情値》が2点上昇し、その属性が《好意》になる。"],
  255. [15, "「なぁ、オレのことどう思う?」思い切った質問!受け身キャラは、攻め気キャラに対する《感情値》を2上昇させ、その属性を好きなものに変更できる。"],
  256. [16, "「あなたのこと心配してるわけじゃないんだからね!」少し前の失敗について色々と言われてしまう。ありがたいんだけど、少しムカつく。受け身キャラは、攻め気キャラに対する《感情値》が2点上昇する。"],
  257. [22, "「え、もうこんな時間!?」一休みするつもりが、気がつくとかなり時間がたっている。この表の使用者のお互いに対する《感情値》が1点上昇し、《アウル》1点を獲得する。"],
  258. [23, "「気になってることがあるんだけど…?」何気ない質問だが、これは難しい。変な答えはできないぞ。攻め気キャラは〔学力〕で判定を行う。成功すると、この表の使用者のお互いに対する《感情値》が成功度の値だけ上昇し、その属性が《好意》になる。失敗すると、何とか危機を切り抜けることができるが、受け身キャラの攻め気キャラに対する《感情値》が1点上昇し、その属性が《敵意》になる。"],
  259. [24, "「なんか面白いとこ連れてって」うーん、これは難しい注文かも?攻め気キャラは、〔政治力〕で判定を行う。成功すると、この表の使用者のお互いに対する《感情値》が成功度の値だけ上昇し、その属性が《好意》になる。失敗すると、何とか危機を切り抜けることができるが、受け身キャラの攻め気キャラに対する《感情値》が1点上昇し、その属性が《敵意》になる。"],
  260. [25, "「うーん、ちょっと困ったことがあってさ」悩みを相談されてしまう。ここはちゃんと答えないと。攻め気キャラは、〔青春力〕で判定を行う。成功すると、この表の使用者のお互いに対する《感情値》が成功度の値だけ上昇し、その属性が《好意》になる。失敗すると、何とか危機を切り抜けることができるが、受け身キャラの攻め気キャラに対する《感情値》が1点上昇し、その属性が《敵意》になる。"],
  261. [26, "「天魔だ。後ろにさがってろ!」何処からとも無く現れた天魔に襲われる。攻め気キャラは好きな能力値で判定を行う。成功すると、この表の使用者のお互いに対する《感情値》が成功度の値だけ上昇し、その属性が《好意》になる。失敗すると、互いに1D6点のダメージを受けつつ、何とか危機を切り抜けることができるが、受け身キャラの攻め気キャラに対する《感情値》が1点上昇し、その属性が《敵意》になる。"],
  262. [33, "「ごめん、勘違いしてた」誤解が解ける。この表の使用者のお互いに対する《感情値》が1点上昇し、《好意》になる。"],
  263. [34, "「これ、キミにしか言ってないんだ。二人だけの秘密」受け身キャラが隠している夢や秘密を攻め気キャラが知ってしまう。受け身キャラの攻め気キャラに対する《感情値》が2点上昇する。"],
  264. [35, "「これからも、よろしく頼むぜ。相棒」攻め気キャラが快活に微笑む。受け身キャラの攻め気キャラに対する《感情値》が2点上昇する。"],
  265. [36, "「わ、わたしは、あなたのことが…」受け身キャラの思わぬ告白!受け身キャラの攻め気キャラに対する《感情値》が2点上昇する。"],
  266. [44, "「大丈夫?痛くないか?」互いに傷を治療しあう。この表の使用者は、お互いの自分に対する[《好意》×1D6]点だけ、自分の《生命力》を回復する事ができる。でちらかの《生命力》が1点以上回復したら、この表の使用者のお互いに対する《感情値》が1点上昇する。"],
  267. [45, "「この事件が終わったら、伝えたい事が…あるんだ」攻め気キャラの真剣な言葉。え、それって…?受け身キャラの攻め気キャラに対する《感情値》が1点上昇し、その属性が《好意》になる。エピローグに攻め気キャラが生きていれば、この表の使用者のお互いに対する《感情値》がさらに2点上昇する。ただし、以降このセッションの間、攻め気キャラは「致命傷表」を使用したとき、二つのサイコロを振って低い目を使う。"],
  268. [46, "「停電ッ!?…って、どこ触ってるんですかッ!?」辺りが不意に暗くなり、思わず変なところを触ってしまう。攻め気キャラの受け身キャラに対する《感情値》が2点上昇し、その属性が《好意》になる。また、受け身キャラの攻め気キャラに対する《感情値》が2点上昇し、その属性が《敵意》になる。"],
  269. [55, "「お前ってそんなやつだったんだ?」意外な一面を発見する。互いに対する《感情値》が1点上昇し、その属性が反転する。"],
  270. [56, "「え?え?えぇぇぇぇッ?!」ふとした拍子に唇がふれあう。受け身キャラの攻め気キャラ以外に対する《感情値》が全て0になり、その値の分だけ攻め気キャラに対する《感情値》が上昇し、その属性が《好意》になる。"],
  271. [66, "「…………」気がつくとお互い、目をそらせなくなってしまう。そのまま顔を寄せ合い…。この表の使用者のお互いに対する《感情値》が3点上昇する。"],
  272. ]
  273. 11 return name, table
  274. end
  275. 1 def getFrindDateTable()
  276. 4 name = "友達デート"
  277. table = [
  278. 4 [11, "「こんなはずじゃなかったのにッ!」\n仲良くするつもりが、ひどい喧嘩になってしまう。この表の使用者のお互いに対する《感情値》が1点上昇し、属性が《敵意》になる。"],
  279. [12, "「……。」\n会話が続かなくて、非常に気まずい。この表の使用者は《生命力》が1D6天回復するが、お互いに対する《感情値》が1点減点する。"],
  280. [13, "「そういえば、キミってアレやってる?」\nお互いの趣味について語り合う。この表の使用者の「好きなもの」の中に近い内容のものを探す。近い内容一つにつき、この表の使用者のお互いに対する《感情値》が1点上昇し、その属性は《好意》になる。"],
  281. [14, "「キミと僕は似ている?」\n攻め気キャラは、受け身キャラと自分の共通点を探す(ジョブやアイテム、髪型やクラス、好き嫌いなど)。1つでも見つけると、攻め気キャラの受け身キャラに対する《感情値》が1点上昇する。属性は攻め気キャラが決定できる。"],
  282. [15, "「いや、全然似てないよ」\n受け身キャラは、攻め気キャラと自分の違うところを探す。3つ以上見つけた場合、受け身キャラの攻め気キャラに対する《感情値》は1点上昇する。属性は受け身キャラが決定できる。"],
  283. [16, "「え、そうだったの!?」\nお互いに意外なところを発見してしまう。この表の使用者のお互いに対する《感情値》が1点上昇し、属性を反転する。"],
  284. [22, "「えーっと、アレがソレでコレになって。\n」非情に当たり障りのない言葉でぼんやりとした会話をする。何も起こらない。"],
  285. [23, "「一緒に体を動かさない?」\n一緒に汗をかいて、リフレッシュ。攻め気キャラの受け身キャラに対する《感情値》が1点上昇し、属性が《好意》になる。受け身キャラは[青春力]で判定を行う。判定に成功すると、受け身キャラから攻め気キャラに対する《感情値》が1点上昇し、属性は《好意》になる。失敗すると、受け身キャラの《アウル》が1点減少する。"],
  286. [24, "「一緒に勉強しようか。」\n一緒に勉強に励む。この表の使用者は[学力]で判定を行う。二人とも成功すると、お互いに対する《感情値》が1点上昇し、属性が《好意》になり、好きな授業の□にチェックを入れる。一人でも失敗すると、攻め気キャラの受け身キャラに対する《感情値》の属性は《敵意》になる。"],
  287. [25, "「一緒に遊ぼうよ!」\n一緒に一つのゲームに向かい合って遊んでみる。お互いに2D6を振る。攻め気キャラの出目が高かった場合、攻め気キャラの受け身キャラに対する《感情値》1点上昇する。受け身キャラの出目が高かった場合、受け身キャラの攻め気キャラに対する《感情値》が2点上昇し、属性は《好意》となる。"],
  288. [26, "「奢るよ。」\n攻め気キャラは、分類「食物」のアイテムを一つ選んで調達判定を行う。成功すると、受け身キャラに調達したアイテムを渡し、受け身キャラの攻め気キャラに対する《感情値》が2点上昇し、属性は《好意》になる。"],
  289. [33, "「交換してみる?」\nこの表の使用者は、武器と防具を一つずつ選ぶ。この表の使用者はお互いに選んだアイテムを交換して、お互いに対する《感情値》が2点上昇し、属性が《好意》になる。このセッションの間、交換したアイテムがこの表の使用者以外の手に渡ったり、消えてしまった場合、この表の使用者はお互いに対する感情の属性は《敵意》になる。"],
  290. [34, "「ショッピングしよう!」\n二人で買い物を始める。攻め気キャラは好きなアイテムを1つ選んで調達判定を行える。調達判定に成功すると、受け身キャラは選んだアイテムを手に入れ、攻め気キャラの《感情値》が1点上昇し、属性は《好意》になる。"],
  291. [35, "「ちょっと休憩しようか。」\n二人でゆっくり過ごす。受け身キャラは、攻め気キャラに対する《感情値》が1点上昇し、属性は《好意》になる。攻め気キャラはプレイスを一つ選び、休憩表を振る。"],
  292. [36, "「二人でやる仕事があるんだけど……。」\n攻め気キャラは好きな能力値で判定を行う。成功すると、続いて受け身キャラが同じ能力値で判定を行う。成功すると、この表の使用者の成功度を足した数と同じだけ【お金】を手に入れる。お互いに対する《感情値》の属性が《好意》になる。どちらかでも失敗すると、お互いに対する《感情値》の属性が《敵意》になる。"],
  293. [44, "「一緒にご飯を食べよう。」\n二人で同じテーブルを囲んでご飯を食べる。この表の使用者は好きなだけ【お金】を消費する。この表の使用者は《生命力》を[消費した【お金】の合計×1]点回復し、お互いに対する《感情値》が[消費した【お金】の合計+1]点上昇し、属性は《好意》になる。"],
  294. [45, "「キミといると楽しいね!」\n会話が弾んで、また遊びたいと思えるような関係になる。この表の使用者はお互いに対する《感情値》が2点上昇し、属性は《好意》となる。さらに、受け身キャラは《感情値》を1点上昇させる。"],
  295. [46, "「あの、さ。」\n悩み事を相談する。受け身キャラは[政治力]で判定を行う。成功すると、攻め気キャラの変調を1つ回復し、攻め気キャラの受け身キャラに対する《感情値》が2点上昇し、属性は《好意》となる。"],
  296. [55, "「ズッ友だよ!」\nこの表の使用者はお互いに対する《感情値》が2点上昇し、属性は《好意》になる。さらに、このセッションの終了フェイズ中、「データのリセット」のタイミングで「自分のアドレスにある《感情値》の合計」を算出する際に、数えなくてもよく、調整もしなくてよい。"],
  297. [56, "「あ。ご、ごめん。」\nふとした拍子に、触れてはならない場所を触れてしまった。受け身キャラの攻め気キャラに対する《感情値》を0にして、元の値と同じだけ攻め気キャラの受け身キャラに対する《感情値》が上昇する。"],
  298. [66, "「実はコイツ……。」\n思っていたよりずっと近かった二人の距離に気付く。この表の使用者のお互いに対する《感情値》が3点上昇し、属性は《好意》になる。"],
  299. ]
  300. 4 return name, table
  301. end
  302. 1 def getOnewayDateTable()
  303. 4 name = "片思いデート"
  304. table = [
  305. 4 [11, "「気付いてくれないあなたが悪いんだから……!」\n突然の告白と、刃物沙汰。撃退士じゃなかったら死んでいた。受け身キャラは《生命力》が3D6点減少する。攻め気キャラの受け身キャラに対する《感情値》が3点上昇し、属性が《敵意》にあんる。受け身キャラは攻め気キャラに対するフラグがあった場合、フラグを折る。"],
  306. [12, "「どうしてあの子の話ばかりするのかな?」\nあの人は、いつもそう。私の前であの子の話ばかり。受け身キャラはこの表の使用者以外のキャラクターを一人選ぶ。攻め気キャラは選ばれたキャラクターに対する《感情値》が2点上昇し、属性が《敵意》になる。"],
  307. [13, "「お仕置き、しないとね。」\n受け身キャラが持っている一番高い《好意》を持っているキャラクターを選ぶ。選ばれたキャラクターは《生命力》を1D6点減少し、攻め気キャラに対する感情の属性が《敵意》になる。選んだキャラクターが攻め気キャラだった場合、攻め気キャラの受け身キャラに対する《感情値》が1点上昇し《生命力》が1D6天回復する。"],
  308. [14, "「負け犬って何のこと?」\n受け身キャラが持っている中で、一番高い《好意》を持っているキャラクターが攻め気キャラでない場合、攻め気キャラの受け身キャラに対するフラグと、受け身キャラの攻め気キャラに対するフラグを折る。攻め気キャラが最も高い場合攻め気キャラは《アウル》を3点回復する。"],
  309. [15, "「何で気づいてくれないの?」\n一方的に思いは募る。攻め気キャラは受け身キャラに対する《感情値》が2点上昇し、属性が《好意》になる。受け身キャラの攻め気キャラに対するフラグがあった場合、フラグを折る。"],
  310. [16, "「贈り物…だよ……。」\n愛情がたくさん入ったアイテム……だけど呪術的なものも入っている気がする。攻め気キャラは好きなアイテムを一つ選び、調達判定を行う。成功した場合、手に入れたアイテムを受け身キャラに渡す。受け身キャラは、渡したアイテムの価格と同じだけ《アウル》が減少する。攻め気キャラは受け身キャラに対する《感情値》が2点上昇する。"],
  311. [22, "「神様、勇気をください。」\n勇気を出して声をかけていく。受け身キャラは攻め気キャラに対する《感情値》が1点上昇し、属性は《好意》になる。"],
  312. [23, "「大変だ!何とかしないと!」\n献身的な看病で、体の調子を戻す。受け身キャラが受けている変調をすべて回復する。攻め気キャラは受け身キャラが持っていた変調をすべて受け、受け身キャラに対する《感情値》が受けた変調と同じ値だけ上昇する。受け身キャラが変調を受けていなかった場合、受け身キャラは【ポーション】を1つ獲得する。"],
  313. [24, "「調べてきたよ!」\n想い人のために、役立つ情報を調べてくる。攻め気キャラは[学力]で判定を行う。成功すると、受け身キャラは好きな授業を一つ選んで□にチェックを入れる。攻め気キャラは受け身キャラに対する《感情値》が1点上昇する。"],
  314. [25, "「どうかこの時間がずっと続きますように。」\n幸せの一瞬。一緒にいるだけでいいのに、時は無情にも過ぎていく。攻め気キャラは《生命力》が限界値まで回復し、《アウル》が2点回復する。ただし、このセッション中に受け身キャラと違うキャラクターとデートを行ったとき、攻め気キャラの《アウル》は0になる。"],
  315. [26, "「お似合いだなんて、そんな……。」\n一緒に歩いているところを冷やかされる。攻め気キャラは受け身キャラに対する《感情値》が2点上昇し、属性は《好意》になる。受け身キャラは攻め気キャラに対するフラグがあった場合フラグを折る。"],
  316. [33, "「応援してるよ!」\n本心を隠して、恋や友情の応援!攻め気キャラは、キャラクターを一人選ぶ。受け身キャラは選ばれたキャラクターに対する《感情値》が2点上昇し、属性が《好意》になる。攻め気キャラが受け身キャラに対するフラグがあった場合、フラグを折る。"],
  317. [34, "「頭が沸騰しそうだよッ!」\n手と手が触れ合って、とても幸せになる。攻め気キャラの《アウル》が受け身キャラに対する《好意》の点数と同じ値だけ回復する。"],
  318. [35, "「あなたは死んでも守る。」\n絶対に守るという固い意志を示す。攻め気キャラの受け身キャラに対する《感情値》が1点上昇する。また、このセッション中に一度だけ、受け身キャラが受けたダメージを代わりに攻め気キャラが受けることができる。"],
  319. [36, "「もう死んでもいいかも……。」\n突然のハプニングでお互い大事なところが触れ合う!思い人と急接近!この表の使用者はお互いに対する《感情値》が1点上昇し属性が《好意》になる。"],
  320. [44, "「何かと必要のはず!」\nお金を工面して、想い人に渡す。受け身キャラは【お金】を1個獲得する。攻め気キャラは受け身キャラに対する《感情値》が1点上昇し、属性は《好意》になる。"],
  321. [45, "「あなたの行きたいところなら!」\n想い人が行くところならどこまでもついて行きますとも。受け身キャラはプレイスを一つ選ぶ。選んだプレイスの休憩表を振って効果を適応する。攻め気キャラは受け身キャラに対する《感情値》が1点上昇し、属性は《好意》になる。"],
  322. [46, "「きっと食べるよね。」\nお菓子を用意して、戻ってくるのを待っている。受け身キャラは《アウル》が1点回復し、攻め気キャラは受け身キャラに対する《感情値》が1点上昇し、属性は《好意》になる。"],
  323. [55, "「肩、揉んであげようか?」\n疲れを察して、率先して動いて休ませてあげる。受け身キャラは《生命力》が1D6点回復し、攻め気キャラに対する《感情値》の属性が《好意》になる。"],
  324. [56, "「贈り物だよっ!」\n愛情がたくさん入ったアイテムを送る。攻め気キャラは好きなアイテムを一つ選び、調達判定を行う。成功した場合、アイテムを受け身キャラに渡す。渡したアイテムの価格の値と同じだけ、攻め気キャラの受け身キャラに対する《感情値》が上昇する。"],
  325. [66, "「そっか、私……。」\n思いが届かないうちに、片思いの相手が他の人と仲良くしているところをみせつけられる。受け身キャラは攻め気キャラ以外のキャラクターを一人選んで《感情値》を3点上昇し、属性を《好意》にする。この表の使用者のお互いに対するフラグがあった場合、フラグを折る。"],
  326. ]
  327. 4 return name, table
  328. end
  329. 1 def getMidnightDateTable()
  330. 4 name = "真夜中デート"
  331. table = [
  332. 4 [11, "「こんなはずじゃなかったのにッ!」\n仲良くするつもりが、ひどい喧嘩になってしまう。この表の使用者のお互いに対する《感情値》が1点上昇し、属性が《敵意》になる。"],
  333. [12, "「夜風が気持ちいい。」\n夜の風が二人を優しく撫でる。落ち着いて話をしよう。この表の使用者は、持っている《感情値》を一つ選んで好きな属性に変更できる。"],
  334. [13, "「夜の散歩に出かけてみようか。」\n攻め気キャラはプレイスを一つ選び、この表の使用者はお互いに選んだプレイスの休憩表を振る。この休憩表によって上昇する《感情値》は二倍になる。"],
  335. [14, "「やべっ、風紀委員だ!」\n風紀委員に見つかって、二人で逃げ回るはめに。この表の使用者はお互いに対する《感情値》の属性を反転させる。"],
  336. [15, "「夜は別の顔があるんだよ。」\n夜はいつもと違った一面を見せる時間だ。攻め気キャラは[政治力]判定を行う。成功すると、受け身キャラに対する《感情値》が2点上昇する。受け身キャラは、攻め気キャラに対する《感情値》の属性を判定させる。"],
  337. [16, "「ね、ねむい。」\n眠くてデートどころではなかったが、寝顔は見られた。受け身キャラは行動の「睡眠」を行い、攻め気キャラは受け身キャラに対する《感情値》が2点上昇し、属性は《好意》になる。"],
  338. [22, "「夜通し遊ぶぜ!」\nついつい張り切ってしまって、夜通し遊んでしまう。この表の使用者はお互いに対する《感情値》が3点上昇し、「眠気」の変調を受ける。"],
  339. [23, "「夜の学校っていいもんだな。」\n夜の学園に忍び込み、二人で探検する。攻め気キャラは1D6を振る。出た目と同じだけ、お互いに対する《感情値》が上昇し、属性が反転する。"],
  340. [24, "「夜の個人授業。」\n夜中の教室で二人だけの授業をする。攻め気キャラは[学力]判定を行う。成功すると、受け身キャラは好きな授業を1つ選び、□にチェックをする。さらに、攻め気キャラの受け身キャラに対する《感情値》1点上昇する。失敗すると、受け身キャラの攻め気キャラに対する《感情値》が2点上昇する。"],
  341. [25, "「怖い話。」\n思い立って、怖い話をしてみる。攻め気キャラは好きな能力値で判定を行う。成功すると、受け身キャラは「恐怖」の変調を受け、受け身キャラに攻め気キャラに対する《感情値》が3点上昇する。受け身キャラは攻め気キャラに対するフラグがあった場合、フラグを折る。"],
  342. [26, "「綺麗な星だな。」\n空を見上げて二人で天体観測。二人の距離はずっと近くに。この表の使用者がお互いに対する《好意》を持っている場合、お互いに対する感情値が1D6点上昇する。"],
  343. [33, "「眼が冴えてきたな。」\n目が冴えてきて、夜中でも問題なく動けそうだ。この表の使用者は、このパートの間「真夜中パートに睡眠を行わなかったキャラクターは、そのパート終了時に1D6点を振って、その目に対応した変調を受けます。」というルールを無効化し、「真夜中デート表」をもう一度振る。"],
  344. [34, "「夜の騎士!」\n夜に紛れて悪さをしようとしていた悪人を懲らしめて戦利品を手に入れる。攻め気キャラは好きな能力値で判定を行う。成功すると、受け身キャラの攻め気キャラに対する《感情値》が判定の成功度だけ上昇する。攻め気キャラは【タバコ】か【お金】を手に入れる。"],
  345. [35, "「いいものアルヨ。」\n妖しいポーションの勧誘に引っかかってしまった。攻め気キャラは[政治力]で判定を行う。判定に成功すると、受け身キャラは《生命力》を1D6点回復し、《感情値》が回復した《生命力》の値と同じだけ上昇し、属性が《好意》になる。判定に失敗すると、受け身キャラは「病気」の変調を受け、《感情値》が2点上昇する。"],
  346. [36, "「私といいことしない?」\n夜闇に乗じて、セクシーな悪魔が誘惑してくる。攻め気キャラは好きな能力値で判定を行う。判定に成功すると、この表の使用者のお互いに対する《感情値》が判定の成功度だけ上昇し、属性は《好意》になる。判定に失敗し、お互いにフラグがあった場合、フラグを折る。"],
  347. [44, "「出歯亀だ!?」\n二人だけの真夜中デートだと思ったら、誰かが見ていたのだ。攻め気キャラは、攻め気キャラでも受け身キャラでもない好きなPCを一人選ぶ。選ばれたPCは、この表の使用者二人に対する《感情値》が2点上昇する。この表の使用者二人は、選ばれたPCに対する感情の属性が《敵意》になる。"],
  348. [45, "「夜の宴が始まる。」\n夜中にパーティーを開き、大騒ぎだ。この表の使用者は、【ごちそう】か【お酒】をすべて消費する。消費した場合、この表の使用者は《生命力》が限界値まで回復し、《アウル》が2点回復する。さらに、お互いに対する《感情値》が2点上昇し、属性が反転する。消費出来なかった場合、何も起こらない。"],
  349. [46, "「月以外、誰も見ていないさ……。」\n見つめ合ったまま、二人の夜が更けていく。この表の使用者はお互いの《感情値》が1D6点上昇し、属性は好きなものを選ぶことができる。"],
  350. [55, "「夜のコスプレショー!」\nお互いに似合うコスチュームを探ってみる。この表の使用者は、同時に「分類:防具/魔装」のアイテムの名前を一つ挙げる(相談禁止)。お互いに同じアイテムの名前を挙げた場合、お互いに対する《感情値》が4点上昇し、挙げたアイテムを一つ獲得する。"],
  351. [56, "「ふー。」\nお互いに色々ぶちまけてスッキリした。この表の使用者は変調をすべて回復し、1D6をどちらかが振る。この表の使用者は、お互いの《感情値》が1D6の目と同じになる。"],
  352. [66, "「帰りの電車がなくなったの……。」\n二人で一夜を過ごす。この表の使用者はお互いに対する《感情値》が5点上昇するが、お互いに「バカ」の変調を受ける。"],
  353. ]
  354. 4 return name, table
  355. end
  356. 1 def changePcName(text, base, name)
  357. 46 then: 2 else: 44 return text if name.nil? || name.empty?
  358. 72 return text.gsub(/(#{base})/) { Regexp.last_match(1) + "(#{name})" }
  359. end
  360. 1 def getDateValue
  361. 5 dice1 = @randomizer.roll_once(6)
  362. 5 return dice1.to_s
  363. end
  364. 1 def getClassRoomBreakTable
  365. 1 name = '教室'
  366. 1 table = [
  367. "風紀委員の巡回!\n「そこ、何やってる!」風紀委員に見つかった。現在が真夜中パートであれば、こっぴどく叱られる。〔政治力〕で判定を行う。失敗すると、次のパートは行動できない。真夜中パート以外であれば、心身ともにリフレッシュ。《アウル》が1点回復する。",
  368. "引き出しのパン\n「お!こんなとこにッ!?」机の中に以前買った食べ物を発見する。アイテムの【焼きそばパン】を一つ獲得する。使用するときに1D6を振ること。奇数が出たら、問題なく使用できる。偶数が出たら、それは腐っている。【焼きそばパン】の効果の変わりに「病気」の変調を受ける事。",
  369. "授業の質問\n「ねぇねぇ、ここ分かる?」クラスメイトに授業の質問を受ける。〔学力〕で判定を行う。成功すると、質問に答えるうちに自分の理解も深まる。自分の授業欄の中から好きなもの一つを選び、□にチェックを入れる。",
  370. "先生の依頼\n「丁度いいところにいるな。手伝ってくれ」先生に用事を言いつけられる。〔政治力〕で判定を行う。成功すると、感謝されてアイテムの【タリスマン】を一つ獲得する",
  371. "誰かの視線\n……誰かの視線を感じる。もしかして? 教室にいるキャラクターの中から好きな者を一人選び、そのキャラクターの自分に対する《感情値》が1点上昇する。(教室に誰がいるのかは、最終的にGMが決定すること)。",
  372. "遊びの誘い\n「ねぇねぇ、明日の放課後ひま?」クラスメイトに遊びに誘われる。翌日の放課後、自由行動として「遊び」を行うことができる。「遊び」を行うと、《アウル》が1D6点回復する。",
  373. "居眠り\n「ZZZ……」教室での居眠りは最高だ。《アウル》1点を変調一つを回復する。ただし、今が授業パートなら、〔青春力〕で判定を行う。失敗すると、先生に怒られて《生命力》が1D6点減少し、《アウル》も変調も回復しない。",
  374. "お腹空いた\n「ねぇねぇ。お腹空いた。なんかない?」クラスメイトに食事をねだられた。分類が「食物」のアイテムを一つ消費することができたら、教室にいるキャラクターの中から好きな者を一人選び、そのキャラクターの自分に対する《感情値》が1点上昇する。",
  375. "クラスの噂\n「ねぇねぇ、これ知ってる?」クラスメイトの噂話……。〔政治力〕の判定を行う。成功すると、手がかり一つを選び、その情報を公開する。失敗すると、あなたについての噂をたてられる。あなたの周囲に、あなたに対して《感情値》を持つキャラクターがいたら、それを反転させる。",
  376. "ラブレター!?\n「こ、これは……ッ!?」机の中に何かを発見。〔青春力〕で判定を行う。成功すると、誰かからのラブレターを発見! 好きなNPC一人を選び、そのキャラクターの自分に対する《感情値》が1点上昇し、属性を《好意》にする。",
  377. "笑い声\n「あはははははは」にぎやかな笑い声が響く。〔青春力〕で判定を行う。成功したら輪の中に溶け込み、《アウル》が1点回復する。失敗すると「孤独」の変調を受ける。",
  378. ]
  379. 1 getBreakTable(name, table)
  380. end
  381. 1 def getSchoolStoreBrakeTable
  382. 1 name = '購買'
  383. 1 table = [
  384. "風紀委員の巡回!\n「そこ、何やってる!」風紀委員に見つかった。現在が授業パートであれば、こっぴどく叱られる。〔政治力〕で判定を行う。失敗すると、次のパートは行動できない。授業パート以外であれば、心身ともにリフレッシュ。《アウル》が1点回復する。",
  385. "まとめ買いセール\n「まとめ買いセール!」好きなアイテムを一つ選ぶ。そのアイテムの調達の判定を一度行う事ができる。このとき、そのアイテムの価格を1高くするたび、追加でもう一個そのアイテムを獲得することができる。",
  386. "防具セール!\n「うわぁ。これ欲しいなぁ」セール品を見つける。分類が「防具」のアイテムの中から好きなものを一つ選ぶ。そのアイテムの価格が1低いものとして調達の判定を一度行うことができる(ただし1未満にはならない)。",
  387. "武器セール!\n「何と!こんなものまで!」セール品を見つける。分類が「武器」のアイテムの中から好きなものを一つ選ぶ。そのアイテムの価格が1低いものとして調達の判定を一度行うことができる(ただし1未満にはならない)。",
  388. "色々セール!\n「ほほう!これはお買い得!」セール品を見つける。分類が「一般」のアイテムの中から好きなものを一つ選ぶ。そのアイテムの価格が1低いものとして調達の判定を一度行うことができる(ただし1未満にはならない)。",
  389. "ウィンドウショッピング\n「へぇ、こんな商品出たんだ」ウインドウショッピングでも、結構気分は晴れるもんだよね。《アウル》が1点回復する。",
  390. "試食\n「お!良かったら食べてみて!」新商品の試食を頼まれる。1D6を振ること。奇数なら美味しさのあまり《生命力》が1D6点と「空腹」の変調が回復する。偶数なら微妙すぎて《生命力》が1点減少する。",
  391. "購買での出会い\n「……あ」陳列棚の商品に伸ばした手と手が触れあう。購買にいるキャラクターの中から好きなキャラクターの自分に対する《感情値》が1点上昇する(購買に誰がいるのかは、最終的にGMが決定すること)。",
  392. "高価買い取り!\n「いいもの持ってるね。よかったら、それ引き取るよ」好きなアイテム一つと【お金】一つを交換することができる。",
  393. "デリバリー\n「あー、今は品切れだねぇ。補充したら届けるよ」好きなアイテムを一つ選ぶ。そのアイテムの調達の判定を一度行うことができる。調達の判定に成功すると、そのアイテムを次のパート以降、好きなタイミングで入手することができる。",
  394. "サイフ紛失\n「あれ? あれれれッ!?」サイフを落としてしまった。【お金】を持っていたら、それを全て失う。",
  395. ]
  396. 1 getBreakTable(name, table)
  397. end
  398. 1 def getClubRoomBrakeTable
  399. 1 name = '部室'
  400. 1 table = [
  401. "風紀委員の巡回!\n「そこ、何やってる!」風紀委員に見つかった。現在が授業パートであれば、こっぴどく叱られる。〔政治力〕で判定を行う。失敗すると、次のパートは行動できない。授業パート以外であれば、心身ともにリフレッシュ。《アウル》が1点回復する。",
  402. "謎の忠告\n「霊があなたに何かを訴えかけようとしてる…」〔政治力〕の判定を行う。成功すると、手がかり一つを選び、その情報を公開する。失敗すると「恐怖」の変調を受ける。",
  403. "後輩現る!\n「どこまでもついていきますよ先輩!」いつのまにか可愛い後輩ができていた。もしも【クラブ】のコミュを修得していたら、アイテムの【後輩】一つを獲得する。",
  404. "先輩現る!\n「おう、さしいれ持ってきたぞ!」先輩がやってくる。アイテムの「ごちそう」を一つ獲得する。",
  405. "青春の汗\n「ダハハハ! 青春の汗を流そうぜ!」部室の中から体育会系部員の熱い会話が聞こえてきた。好きな能力値で判定を行う。成功すると、このセッションの間、〔青春力〕の修整が1点上昇する。失敗すると「バカ」の変調を受ける。",
  406. "茶飲み話\n「まぁまぁ。お茶でも飲んでいきなよ」知り合いの所属する部室でお茶を飲む。〔政治力〕の判定を行う。成功すると、《アウル》が1点回復する。",
  407. "熱い議論「もっと本質的な部分に目を向けようよ!」部室の中から文科系部員の高度な会話が聞こえてきた。好きな能力値で判定を行う。成功すると、このセッションの間、〔学力〕の修整が1点上昇する。失敗すると「孤独」の変調を受ける。",
  408. "マネージャー\n「あれ? ケガしてるじゃないですか」もしも【クラブ】のコミュを修得していたら、可愛いマネージャーが絆創膏をくれる。《生命力》が1D6点回復する。",
  409. "突然の料理\n「ちょっと付き合えよ」もしも【クラブ】のコミュを修得していたら、仲間の部員に呼び止められる。〔政治力〕で判定を行う。成功すると、自分の放課後欄の中から好きな【クラブ】一つを選び、□にチェックを入れる。",
  410. "仲間の告白\n「キミ、最近なんかいい感じだよね」もしも【クラブ】のコミュを修得していたら、部室にいるキャラクターの中から好きな者を一人選び、そのキャラクターの自分に対する《感情値》が1点上昇する(部室に誰がいるのかは、最終的にGMが決定する事)",
  411. "門外不出品?\n「なんだこれ……?」部室の奥から、いわれのありそうな古書が出てくる。外国の言葉で書かれているみたいだけど……?〔学力〕で判定を行う。必要な成功度は、自分のカオスレートの絶対値となる(1未満にはならない)。成功すると、そのセッションの間、自分のカオスレートを1点上昇するか、1点減少する。",
  412. ]
  413. 1 getBreakTable(name, table)
  414. end
  415. 1 def getStudentCouncilBrakeTable
  416. 1 name = '生徒会室'
  417. 1 table = [
  418. "風紀委員の巡回!\n「そこ、何やってる!」風紀委員に見つかった。現在が真夜中パートであれば、こっぴどく叱られる。〔政治力〕で判定を行う。失敗すると、次のパートは行動できない。真夜中パート以外であれば、心身ともにリフレッシュ。《アウル》が1点回復する。",
  419. "秘密の会話\n「これ……極秘……はい……早急……対処……」生徒会質の面々の内緒話が漏れ聞こえてくる。これはいいことを聞かせてもらった。次に自分が調査の判定を行ったとき、その達成値が3点上昇する。",
  420. "天魔情報\n「むむ!これは……」天魔に対する情報を検索していたら、気になる情報が……。〔学力〕の判定を行う。成功すると、このシナリオに登場する可能性のある天魔の種類すべてをGMから教えてもらえる。",
  421. "気になるあいつ\n「不運。そういう名前なのか、あいつ」もしこのシナリオに登場しているNPCで、名前がわからないキャラクターがいたら、それを知ることができる。また、「好きなもの」と「嫌いなもの」が分からないキャラクターがいたら、「単語表」を使ってランダムに決める事ができる。",
  422. "調べられてる?\n「あれ、これって……?」誰かが自分のことを検索した形跡がある。〔政治力〕で判定を行う。成功すると、自分について調査していた人物を発見!好きなNPC一人を選び、そのキャラクターの自分に対する《感情値》が1点上昇する。",
  423. "プロフィール更新\n「自分のプロフィールを更新しておこう」〔政治力〕で判定を行う。成功すると、好きなキャラクター一人を選ぶ。そのキャラクターの自分に対する《感情値》の属性を《好意》にすることができる。",
  424. "思わぬ一面\n「へぇ。こいつって、こんなヤツだったんだ」生徒会質で知り合いの思わぬ一面を知る。自分が《感情値》を持っているキャラクター一人を選ぶ。そのキャラクターへの《感情値》の属性を反転する。",
  425. "友達検索\n「折角なんで、あいつのこと調べてみるか」友人の情報を検索してみる。〔政治力〕で判定を行う。成功すると、PCの中から好きなキャラクター一人を選ぶ。そのキャラクターに対する《感情値》が1点上昇する。",
  426. "同僚との遭遇\n「こんなとこで何してんの?」もしも【委員会】のコミュを修得していたら、仲間の委員に呼び止められる。〔政治力〕で判定を行う。成功すると、自分の放課後欄の中から好きな【委員会】一つを選び、□にチェックを入れる。",
  427. "旧友との再会\n「おう!久しぶりッ!!」昔の友人とばったり再会。〔青春力〕の判定を行う。成功すると、昔貸していた本を返してくれる。アイテムの【参考書】を一つ獲得する。",
  428. "謎の警告\n「深追いはするな。これは警告だ」携帯電話に謎の脅迫メールが届く。何者かに目をつけられたようだ。〔政治力〕で判定を行う。失敗すると「恐怖」の変調を受ける。",
  429. ]
  430. 1 getBreakTable(name, table)
  431. end
  432. 1 def getDormitoryBrakeTable
  433. 1 name = '学生寮'
  434. 1 table = [
  435. "風紀委員の巡回!\n「そこ、何やってる!」風紀委員に見つかった。現在が授業パートであれば、こっぴどく叱られる。〔政治力〕で判定を行う。失敗すると、次のパートは行動できない。授業パート以外であれば、心身ともにリフレッシュ。《アウル》が1点回復する。",
  436. "友達との時間\n「だよねー」友達の部屋でお茶とお菓子をごちそうになる。《生命力》が1D6点、《アウル》が1点回復する。",
  437. "思い出の日\n寮の友人とハメを外して、寮長に怒られる。学生寮にいるキャラクターの中から好きな者を一人選ぶ。自分とそのキャラクターは「バカ」の変調を受け、お互いに対する《感情値》が2点上昇する(寮に誰がいるのかは、最終的にGMが決定する事)。",
  438. "引越しの手伝い\n「あ、今日からここに住む者です。よろしく」行きがかり上、引越しの手伝いをすることに。〔青春力〕で判定を行う。成功すると、感謝されてアイテムの【ごちそう】を一つ獲得する。",
  439. "色々トーク\n友達を自分の部屋に呼んでボーイズトーク!ガールズトーク♪ 「青春力」の判定を行う。成功すると、自分に対して《好意》を持っている同姓のキャラクター全員の、自分に対する《感情値》が1点上昇する。判定に失敗するか、自分に対して《好意》を持っているキャラクターが一人もいないと「孤独」の変調を受ける。",
  440. "好物発見!\n「お、ラッキー♪」冷蔵庫の中に好物を発見。分類が「食物」のアイテムの中から好きなものを一つ選ぶ。それを一つ獲得する。使用するときに1D6を振ること。奇数が出たら、問題なく使用できる。偶数が出たら、それは腐っている。そのアイテムの効果の代わりに「病気」の変調を受ける事。",
  441. "お見舞い\n「ねぇ、大丈夫?」もしも「病気」か「孤独」の変調を受けていたら、友人がお見舞いに来てくれる。好きなキャラクター一人を選ぶ。自分とそのキャラクターは、お互いに対する《感情値》が1点上昇する。そして好きな変調一つが回復する。",
  442. "魔蟲襲来!\n「カサカサカサ……」黒くて素早く動くアイツが現れた!〔学力〕で判定を行う。失敗すると、《アウル》が1点減少する。",
  443. "恋の相談\n寮の友人から恋人に関する相談を受ける。もしも【恋人】のコミュを修得していたら、《アウル》が2点回復する。修得していなかったら「孤独」の変調を受ける。",
  444. "寮に潜入\n「こっそり遊びにきてみない?」異性の友人を呼んでスリルを味わう。好きなキャラクター一人を選び、「青春力」で判定を行う。成功すると、自分とそのキャラクターは《アウル》が2点回復する。失敗すると、互いに対する《感情値》が1点減少する。",
  445. "ささいなケンカ\n「なんだとーッ!」「なにをーッ!」ささいな行き違いから、他の住人とケンカになってしまう。〔青春力〕か〔政治力〕で判定を行う。〔青春力〕の判定に失敗すると《生命力》が2D6点減少する。〔政治力〕の判定に失敗すると「孤独」の変調を受ける。",
  446. ]
  447. 1 getBreakTable(name, table)
  448. end
  449. 1 def getLibraryBrakeTable
  450. 1 name = '図書館'
  451. 1 table = [
  452. "風紀委員の巡回!\n「そこ、何やってる!」風紀委員に見つかった。現在が授業パートであれば、こっぴどく叱られる。〔政治力〕で判定を行う。失敗すると、次のパートは行動できない。授業パート以外であれば、心身ともにリフレッシュ。《アウル》が1点回復する。",
  453. "重たい空気\n静かな気配に圧倒される。とりあえず手近にあった本のページを開いてみるが……。〔学力〕で判定を行う。失敗すると「バカ」の変調を受ける。",
  454. "文献調査\n「過去にも似たような事件があったようだ」文献を調べる。次に自分が調査の判定を行ったとき、その達成値が3点上昇する。",
  455. "天魔対策\n「アイツの習性は……」天魔の事を調べる。天使か悪魔のエネミー一種を選んで、〔学力〕の判定を行う。成功すると、そのセッションの間、そのエネミーの攻撃に対して、ガード判定を行う場合、その達成値が2点上昇する。",
  456. "物語の世界へ\n「…………」シーンと静まり返った雰囲気の中、読書が進む。本の中にどんどん入り込んでいく。すべての変調が回復し、「空腹」の変調を受ける。",
  457. "本の貸し出し\n「へー、こんな本もあるんだ」アイテムの【週刊誌】か【参考書】のいずれか一つを獲得する。",
  458. "授業の予習\nせっかく図書館に来たので、気になっていた科目について調べる。〔学力〕で判定を行う。成功すると、疑問点が解消される。自分の授業欄の中から好きなものを一つ選び、□にチェックを入れる。",
  459. "図書館での出会い\n「……あ」書架の本に伸ばした手と手が触れ合う。図書館にいるキャラクターの中から好きな者を一人選び、そのキャラクターの自分に対する《感情値》が1点上昇する(図書館に誰がいるのかは、最終的にGMが決定する事)。",
  460. "書物の夢\n本を読んでいるうちにいつの間にか眠ってしまったようだ。何か面白い夢を見たような気がするんだけど……うーん、まだ眠い。「眠気」の変調を受け、《アウル》が2点回復する。",
  461. "謎の手紙\n「……ッ!?」本を開いてみると、そこにはあなた宛の手紙が……どうして、この本を読む事が分かったんだろう。〔青春力〕で判定を行う。成功すると、手がかり一つを選び、その情報を公開する。失敗すると、「恐怖」の変調を受ける。",
  462. "残念!\n目当ての本はすでに借りられていた。残念!《アウル》が1点減少する。",
  463. ]
  464. 1 getBreakTable(name, table)
  465. end
  466. 1 def getRoofBrakeTable
  467. 1 name = '屋上'
  468. 1 table = [
  469. "風紀委員の巡回!\n「そこ、何やってる!」風紀委員に見つかった。現在が授業パートであれば、こっぴどく叱られる。〔政治力〕で判定を行う。失敗すると、次のパートは行動できない。授業パート以外であれば、心身ともにリフレッシュ。《アウル》が1点回復する。",
  470. "通り雨\n「キャ〜〜〜〜!」突然雨がふってきた!みんな屋上を去っていく。屋上にいるキャラクターの中から好きな者を一人選び、そのキャラクターの自分に対する《感情値》が1点上昇する(屋上に誰がいるのかは、最終的にGMが決定すること)。",
  471. "自動販売機\n「なんで屋上に自動販売機があるんだ?」細かい事は気にせず何かのもう。〔政治力〕の判定を行う。成功すると、アイテムの【ポーション】か【お酒】か【タバコ】のいずれか一つを獲得できる。",
  472. "青空\n空を見上げると、自分がちっぽけな存在に思えてくる。〔青春力〕で判定を行う。成功すると、使用回数に制限がある授業かコミュを一つ選ぶ。その使用回数が一度分回復する。",
  473. "物思い\n空をながめながら、物思いにふける。俺ってアイツの事、どう思ってるんだろう?〔青春力〕で判定を行う。成功すると、PCの中から好きなキャラクター一人を選ぶ。そのキャラクターに対する、《感情値》が1点上昇する。",
  474. "開放感\n開放的で非常に気分がいい。《アウル》が1点と「眠気」の変調が回復する。",
  475. "学園は広大だわ\n街並みを見下ろす。一体、この学園で何が起きているんだろう?〔学力〕で判定を行う。成功すると手がかり一つを選び、その情報を公開する。失敗すると、ほかの学生たちの姿が目に映り、今の自分に疑問がわいてくる。《アウル》が1点減少する。",
  476. "嵐の予感\n雲の動きが早くなっている。吹き荒ぶ風に、嵐の予感を感じた。〔青春力〕で判定を行う。成功すると、そのセッションの間、《アウル》の限界値が1点上昇する。失敗すると風に吹かれて風邪をひいてしまう。「病気」の変調を受ける。",
  477. "昼寝屋\nハンモックを貸し出している「昼寝屋」を発見。気持ちよさそうだ。〔政治力〕で判定を行う。成功すると、《生命力》が2D6点と「眠気」の変調が回復する。",
  478. "欲望の宴\n美味しそうな弁当を食べる者、恋人同士でイチャイチャするもの、怠惰な眠りを貪る者……屋上は欲望の見本市のようだ。「空腹」、「孤独」、「眠気」の内、好きな変調を受けることができる。受けた変調一種につき《アウル》が2点回復する。",
  479. "サビシガリヤ\n「……あなたも一人?」もしも「孤独」の変調を受けていたら、寂しそうな異性に声をかけられる。好きな異性のキャラクター一人を選ぶ。自分とそのキャラクターは、お互いに対する《感情値》が2点上昇する。そして好きな変調一つが回復する。",
  480. ]
  481. 1 getBreakTable(name, table)
  482. end
  483. 1 def getLaboratoryBrakeTable
  484. 1 name = '研究室'
  485. 1 table = [
  486. "風紀委員の巡回!\n「そこ、何やってる!」風紀委員に見つかった。現在が真夜中パートであれば、こっぴどく叱られる。〔政治力〕で判定を行う。失敗すると、次のパートは行動できない。真夜中パート以外であれば、心身ともにリフレッシュ。《アウル》が1点回復する。",
  487. "装甲強化実験\n「ほう。面白い防具を使っているようだな」白衣を着た怪しげな生徒が防具の改造を申し出る。申し出を受け入れるなら、自分のもっている好きな防具一つを選んで、1D6を振る。奇数が出ると、そのセッションの間、その防具の装甲が1上昇する。偶数が出ると、その防具は破壊される。",
  488. "試薬\n「この試薬を飲んでみてくれないか」毒々しい色のポーションを渡される。「政治力」で判定を行う。失敗すると、断りきれずそれを飲むハメになる。。1D6を振る。奇数が出ると《生命力》が2D6点、《アウル》が1点回復する。偶数が出ると、「恐怖」と「病気」の変調を受ける。",
  489. "爆発事故\n「逃げろー!」研究室から数人の生徒が逃げ出してくる。なにかヤな予感。〔青春力〕で判定を行う。失敗すると、実験の爆発に巻き込まれる。《生命力》に2D6点のダメージを受ける。",
  490. "威力強化実験\n「ほう。面白い武器を使っているようだな」白衣を着た怪しげな生徒が武器の改造を申し出る。申し出を受け入れるなら、自分のもっている好きな武器一つを選んで、1D6を振る。奇数が出ると、そのセッションの間、その武器の威力が1上昇する。偶数が出ると、その武器は破壊される。",
  491. "命中強化実験\n「ほう。面白い武器を使っているようだな」白衣を着た怪しげな生徒が武器の改造を申し出る。申し出を受け入れるなら、自分のもっている好きな武器一つを選んで、1D6を振る。奇数が出ると、そのセッションの間、その武器に「精度2」の特殊効果が加わる(すでに「精度」の特殊効果のある武器は、その値が2上昇する)。偶数が出ると、その武器は破壊される。",
  492. "威力安定実験\n「ほう。面白い武器を使っているようだな」白衣を着た怪しげな生徒が武器の改造を申し出る。申し出を受け入れるなら、自分のもっている好きな武器一つを選んで、1D6を振る。奇数が出ると、そのセッションの間、その武器に「安定性3」の特殊効果が加わる(すでに「安定性」の特殊効果のある武器は、その値が1上昇する)。偶数が出ると、その武器は破壊される。",
  493. "バイオハザード\n「ピーーーー!ピーーーー!ピーーーー!」不吉な警告音が鳴り響く。バ、バイオハザードッ!?〔政治力〕で判定を行う。失敗すると、実験施設から漏れ出した奇妙な細菌に感染する。1D6を二回振って、ランダムに変調を二つ選び、それを受ける。",
  494. "ビーカーコーヒー\n「一杯やるかい?」ビーカーに注がれた珈琲を貰う。結構美味いんだけど、ちゃんと洗ってるのかな?「眠気」と「空腹」の変調が回復する。",
  495. "装甲安定実験\n「ほう。面白い防具を使っているようだな」白衣を着た怪しげな生徒が防具の改造を申し出る。申し出を受け入れるなら、自分のもっている好きな防具一つを選んで、1D6を振る。奇数が出ると、そのセッションの間、その防具に「堅牢2」の特殊効果が加わる(すでに「堅牢」の特殊効果のある防具は、その値が2上昇する)。偶数が出ると、その防具は破壊される。",
  496. "失敗作\n「そいつは失敗作だよ。欲しければ持っていって構わない」価格が3以下の好きなアイテム一つを選ぶ。それを一個獲得する。このアイテムは、持ち主がファンブルすると、破壊される。",
  497. ]
  498. 1 getBreakTable(name, table)
  499. end
  500. 1 def getPoolBrakeTable
  501. 1 name = 'プール'
  502. 1 table = [
  503. "風紀委員の巡回!\n「そこ、何やってる!」風紀委員に見つかった。現在が授業パートであれば、こっぴどく叱られる。〔政治力〕で判定を行う。失敗すると、次のパートは行動できない。授業パート以外であれば、心身ともにリフレッシュ。《アウル》が1点回復する。",
  504. "熱いシャワー\n「……ふぅ」プールから出て、暖かいシャワーで冷えた体を暖める。疲れが少しずつほぐれていく。《生命力》が1D6点回復する。",
  505. "新作水着\n新しい水着の評判はどうかな?〔青春力〕の判定を行う。成功すると、プールにいるキャラクターの中から好きな者をその成功度と同じ人数だけ選び、そのキャラクターの自分に対する《感情値》が1点上昇する(プールに誰がいるのかは、最終的にGMが決定すること)。",
  506. "ポロリもあるよ\nプールからあがろうとしたき、思わず水着がポロリ。げげ。今の誰か見てたッ!?周囲にいる異性のキャラクターの自分に対する《感情値》の属性が反転する。",
  507. "熱視線\n誰かが、美しいフォームで飛び込み、水しぶきがあがる。思わず見惚れてしまう。プールにいるキャラクターの中から好きな者を一人選び、自分のそのキャラクターに対する《感情値》が1点上昇する(プールに誰がいるのかは、最終的にGMが決定すること)。",
  508. "眼福眼福\n水着がまぶしい!いい眺めかも……。《アウル》が1点回復する。",
  509. "人魚のように\n華麗なターンが決まり、周囲から賞賛の声があがる。プールにいるキャラクターの中から好きな者を一人を選び、そのキャラクターの自分に対する《感情値》が1点上昇する(プールに誰がいるのかは、最終的にGMが決定すること)。",
  510. "プカプカ\n水に浮かんでのんびりプカプカ。《アウル》が1点回復する。",
  511. "心地よい疲れ\n結構長い時間泳いだぞ。いい運動になったけど、お腹ペコペコダー。「空腹」の変調を受け、そのセッションの間、《生命力》の限界値が1D6点上昇する。",
  512. "記録に挑戦!\n「今日は、どこまで泳げるかな?」」自己新記録に挑戦!〔学力〕で判定を行う。成功すると、自己新記録を更新して《アウル》が2点回復する。失敗すると、溺れてしまう。《生命力》を2D6点減少する。",
  513. "地獄の特訓\n様々な地獄プールで特訓!みっちり自分の体をおいじめて、鍛えたぞ。〔青春力〕の判定を行う。成功すると、《生命力》が2D6点減少し、そのセッションの間、《生命力》の限界値が減少した《生命力》と同じ値だけ上昇する。",
  514. ]
  515. 1 getBreakTable(name, table)
  516. end
  517. 1 def getInnerCourtBrakeTable
  518. 1 name = '中庭'
  519. 1 table = [
  520. "風紀委員の巡回!\n「そこ、何やってる!」風紀委員に見つかった。現在が授業パートであれば、こっぴどく叱られる。〔政治力〕で判定を行う。失敗すると、次のパートは行動できない。授業パート以外であれば、心身ともにリフレッシュ。《アウル》が1点回復する。",
  521. "オープンカフェ\nカフェテリアでお茶にする。優雅なひと時。《アウル》が1点回復する。",
  522. "犬登場\n「ワンワンワン!」不思議な犬がグラウンドに現れる。ここを掘れと言っているようだが……。1D6を振ること。奇数なら、地面にはお金が埋まっていた【お金】を一つ獲得する。偶数なら、低級の天魔が封印されていた。「学力」で判定を行う。失敗すると《生命力》に3D6点のダメージを受ける。",
  523. "観戦中\nグラウンドで行われている撃退士同士の特訓風景を眺めている。踏む。なるほどなぁ……。〔学力〕で判定を行う。成功すると、自分の授業欄の中から好きなものを一つ選び、□にチェックを入れる。",
  524. "占い師\n「そこのあなた。死相がでています。」そう言って、占い研のメンバーに呼び止められる。〔政治力〕の判定を行う。成功すると、危険を回避する方法を占ってもらうことができる。次に自分が判定で大失敗したとき、その判定のサイコロを1度だけ振り直すことができる。",
  525. "屋台\nお弁当屋さんや屋台が軒を並べている。美味しそうな匂いが漂ってきた。〔政治力〕の判定を行う。成功すると、色々な食事を食べて、《生命力》が1D6点と「空腹」の変調が回復する。",
  526. "特訓参加\n「おい、そこのお前!お前も一緒にやれ!」授業中の先生に、無理やり授業に参加させられる。ひたすら攻撃を避けまくる。ふは。疲れたー。《生命力》が2D6点減少し、そのセッションの間、《生命力》の限界値が減少した《生命力》と同じ値だけ上昇する。",
  527. "落し物\nあれ?こんなものが落ちてる。どうしたんだろう? 1なら【タバコ】、2なら【情報誌】、3なら【お洒落グッズ】、4なら【参考書】、5なら【阻霊符】、6なら【タリスマン】を一個獲得する。",
  528. "突然の告白!\n「先輩、ずっと前から憧れてました!」そう言って、後輩が告白して来た。え?ええッ!?突然の事に頭が真っ白になってしまった。好きな異性のキャラクター一人を選ぶ。そのキャラクターの自分に対する《感情値》が2点上昇する。その後、〔青春力〕で判定を行う。失敗すると「バカ」の変調を受ける。",
  529. "鉄球飛来!\n「おーい!危ないぞーッ!!」陸上部の投げた砲丸が飛んでくる。〔青春力〕で判定を行う。失敗すると《生命力》に2D6点のダメージを受ける。",
  530. "ちょっぴり贅沢\n今日は自分にご褒美。学食で贅沢しちゃおっかなー〔政治力〕で判定を行う。成功すると《生命力》が2D6点と《アウル》1点が回復する。",
  531. ]
  532. 1 getBreakTable(name, table)
  533. end
  534. 1 def getShoppingAvenueBrakeTable
  535. 1 name = '商店街'
  536. 1 table = [
  537. "風紀委員の巡回!\n「そこ、何やってる!」風紀委員に見つかった。現在が授業パートであれば、こっぴどく叱られる。〔政治力〕で判定を行う。失敗すると、次のパートは行動できない。授業パート以外であれば、心身ともにリフレッシュ。《アウル》が1点回復する。",
  538. "自習\nファーストフード店でレポート執筆。……あまり進まないなぁ。〔学力〕で判定を行う。成功度を2以上獲得すると、レポートは完成。自分の授業欄の中から好きなもの一つを選び、□にチェックを入れる。",
  539. "立ち話\n「よう。寄ってかないかい!」店の主人が陽気に声をかけてくる。〔政治力〕で判定を行う。成功すると、気になる話を聞かせてくれる。手がかり一つを選び、その情報を公開する。失敗すると、退屈な話に付き合わされる。「眠気」の変調を受ける。",
  540. "雰囲気のいい店\n「へぇ。こんな店あったんだ」とても雰囲気のいい店を見つける。次に自分がデート判定を行うとき、その達成値が2点上昇する。",
  541. "お気に入り!\n「おお!すごくいいッ!!」とってもこのみなオシャレアイテムを見つける。〔政治力〕の判定を行う。成功すると、アイテムの〔お洒落グッズ〕一個を獲得し、《アウル》1点を獲得する。",
  542. "大売出し\n「スーパークリアランスバザール!」お買い得なキャンペーンをやっている。アイテムの中から好きなものを一つ選ぶ。そのアイテムの価格が1低いものとして調達の判定を一度行う事ができる(ただし1未満にはならない)",
  543. "なじみの店\n先輩のアルバイトしているお店に遊びに行ってみた。色々サービスしてくれて大満足。《生命力》1D6点と《アウル》1点を回復する。",
  544. "休日\nお目当ての店に行ってみたら、シャッターが閉まっていた。どうやら臨時休業の模様。がっくりきて、《アウル》を1点減少する。",
  545. "泥棒\n「泥棒よー!捕まえてー!」商店街を走って逃げる不良生徒たち……捕まえるなら〔青春力〕で判定を行う。成功すると、泥棒を捕まえ、そのお礼としてアイテムの〔ポーション〕か〔タリスマン〕を一つ獲得する。失敗すると、泥棒を逃がした上に商店街の色々な場所を壊してしまい、しばらく出入り禁止に。このセッションの間、商店街で休憩を行うことができなくなる。",
  546. "福引\n福引をやっていた!1D6を振る。1〜5の目がでたら残念賞。アイテムの【焼きそばパン】一つを手に入れる。6の目がでたら【お金】を二つ手に入れる。",
  547. "家庭教師\n「ねぇねぇ、教えて酔う」近所の子供に勉強を教えてくれと頼まれる。〔学力で〕判定を行う。成功すると、彼らは尊敬の目できみを見つめる。アイテムの【後輩】を一つ獲得する。失敗すると「バカ」の変調を受ける。",
  548. ]
  549. 1 getBreakTable(name, table)
  550. end
  551. 1 def getDevastationBrakeTable
  552. 1 name = '廃墟'
  553. 1 table = [
  554. "迷子\n「きゃーーー!」少女がディアボロに襲われている。〔青春力〕で判定を行う。成功すると、少女を助けて感謝される。少女の自分に対する《感情値》が3点上昇し、その属性が《好意》になる。失敗すると、少女は命は取り留めたものの、傷つき倒れてしまう。《生命力》に2D6点のダメージと「孤独」変調を受ける。",
  555. "ライバル登場?\n「一度、お前と手合わせしてみたかったんだよ」撃退士らしき見覚えある人物が現れる。好きなNPCを一人選び、そのキャラクターの自分に対する《感情値》が1点上昇する。",
  556. "無人の部屋\n「…………」誰もいないはずなのに、何かの気配がする。イヤな感じだ。〔青春力〕で判定を行う。成功すると、視線の正体を発見する。それはかわいい子猫だった。あまりのかわいらしさに《アウル》を1点獲得する。失敗すると「恐怖」の変調を受ける。",
  557. "戦いの跡\n戦いがあったであろう場所に、一振りの剣が突き刺さっていた。この剣の持ち主はどうなったんだろう…?アイテムの【大剣】一個を獲得する。",
  558. "裏の事情通\n「あんたの知りたい情報を売ってやろうか?」情報屋らしき男が情報の購入を持ちかける。手がかり一つを選び、調達の判定を一度行うことができる。情報の価格は、手がかりの[必要成功度-1(1未満にはならない)]になる。情報の調達に成功すると、その情報を公開する。",
  559. "怪しげな男\n「いいものがあるぜ。欲しいかい?]怪しげな男が【ポーション】を打っている。アイテムの【ポーション】の調達の判定を一度行うことができる。この【ポーション】の価格は3になるが、回復する《生命力》は3D6点になる。",
  560. "縄張り\n「おいおい、ここは俺たちの縄張りだぜ]不良たちに絡まれる。〔政治力〕で判定を行う。成功すると、不良たちは捨て台詞と共に逃げ出す。もし、廃墟に自分に対して《敵意》の属性の《感情値》の持ち主がいた場合、その属性を反転する(廃墟に誰がいるのかは、最終的にGMが決定すること)。失敗すると、1D6点のダメージを受ける。",
  561. "野良犬\n「グルルルルルッ!」野良犬たちが牙をむいている。〔青春力〕の判定を行う。失敗すると2D6点のダメージを受ける。",
  562. "隠れ家\n「学園だとどうしても気分が出なくてなぁ」【酒】か【タバコ】を何個でも使用することができる。ここで【酒】か【タバコ】を一個使用するたびに追加で《アウル》が1点回復する。また、ここで【酒】や【タバコ】を使った場合、その効果によって「眠気」や「孤独」の変調を受けない。",
  563. "実験\n「一度試してみたかったんだよな]ここでなら思い切り暴れても特に問題なさそうだ。あの技を試してみるか……。[青春力]で判定を行う。成功すると、自分の授業欄の中から好きなもの一つを選び、□にチェックを入れる。",
  564. "不良撃退士\n「ほう。いいもの持ってるじゃないか。そいつを寄こしたら見逃してやるよ」自分の携行品の中で一番価格の高いものを一つ選ぶ。それを渡せば特に何も起こらない。もし渡すのを断るのなら、〔青春力〕で判定を行う。成功度が2以下だった場合、3D6点のダメージを受ける。",
  565. ]
  566. 1 getBreakTable(name, table)
  567. end
  568. 1 def getGateBrakeTable
  569. 1 name = 'ゲート'
  570. 1 table = [
  571. "尋問\nゲート内にひそんでいた天魔から情報を収集する。〔政治力〕の判定を行う。成功すると、このシナリオに登場する可能性のある天魔の種類すべてをGMから教えてもらえる。失敗すると、1D6点のダメージを受ける。",
  572. "計略\n敵の計略に掛かる。〔政治力〕で判定を行う。失敗すると、GMは手がかり一つを選ぶ。その手がかりの必要成功度が1上昇する。この効果は累積しない。",
  573. "活性化\n戦いを通じて、《アウル》の使い方を学んで行く。〔学力〕で判定を行う。成功すると、《アウル》を2点回復する。失敗すると、1D6点のダメージを受ける。",
  574. "克服\n無数の敵と戦ううちに、心が研ぎ澄まされていく。好きな能力地で判定を行う。成功すると、その成功度と同じ数だけ変調を回復する。失敗すると、1D6点のダメージを受ける。",
  575. "経験\nゲート内で多くの天魔と戦う。好きな能力値で判定を行う。成功すると、その成功度の数と同じだけ、成長欄のまだチェックの入っていない□をチェックする事ができる。失敗すると、1D6点のダメージを受ける。",
  576. "不意打ち\n「……あれは、もしや?]ゲートの中で、恐ろしい程の殺気の持ち主を見かける。もしや、今回の事件の黒幕か?彼に不意打ちを仕掛けることができる。不意打ちを仕掛けるなら〔青春力〕の判定を行う。成功すると、そのシナリオの黒幕(ボス)に[判定成功度×1]D6点のダメージを与える事ができる。失敗すると、3D6点のダメージを受ける。",
  577. "捜索\nゲート内を捜索する。〔学力〕で判定を行う。成功すると、「初期アイテム決定表」を一度使用し、そのアイテム一個を獲得する。失敗すると、1D6点のダメージを受ける。",
  578. "戦友\n一緒に敵と戦ううちに、絆が芽生えてくる。〔青春力〕で判定を行う。成功すると、ゲートにいるキャラクターの中から好きなものを一人選ぶ。自分とそのキャラクターは、お互いに対する《感情値》が1点上昇する(ゲートに誰がいるのかは、最終的にGMが決定すること)。失敗すると1D6点のダメージを受ける。",
  579. "援軍\nゲートには大量の敵が待ち構えていた。〔政治力〕のはんていを行う。成功すると、仲間が助けに来てくれて逃げ出すことができる。アイテムの【ポーション】を一つ獲得する。失敗すると、1D6点のダメージを受ける。",
  580. "罠\nゲートに仕掛けられた罠が発動する!〔学力〕で判定を行う。失敗すると、1D6点のダメージとランダムに選んだ変調一つを受ける。",
  581. "魔剣\n敵と戦う内に、武器の切れ味が鋭くなっている。〔学力〕で判定を行う。成功すると好きな武器一つを選ぶ。このセッションの間、威力が1点上昇する。失敗すると、1D6点のダメージを受ける。",
  582. ]
  583. 1 getBreakTable(name, table)
  584. end
  585. 1 def getBreakTable(name, table)
  586. 13 number = @randomizer.roll_sum(2, 6)
  587. 13 index = number - 2
  588. 13 text = table[index]
  589. 13 then: 0 else: 13 return '' if text.nil?
  590. 13 return "#{name}休憩表(#{number}) #{text}"
  591. end
  592. 1 def getD6Table(name, table)
  593. 3 number = @randomizer.roll_once(6)
  594. 3 index = number - 1
  595. 3 text = table[index]
  596. 3 then: 0 else: 3 return '' if text.nil?
  597. 3 return "#{name}(#{number}) #{text}"
  598. end
  599. 1 def getBattleFieldTable
  600. 1 name = '戦場表'
  601. 1 table = [
  602. "平地。\n特に特殊効果はない。",
  603. "罠。\n落とし穴やセキュリティー装置など、無数の罠が仕掛けられた戦場。この戦場にいるキャラクターは、ダメージを受けたとき、速度によるダメージ修整が2倍になる。",
  604. "障害物。\n林の中や狭い部屋の中など、自由に身動きすることが難しい戦場。この戦場にいるキャラクターは、プロットを行うとき、5以上の速度をプロットできなくなる。",
  605. "機動戦\n車や電車、船や飛行機など、動いているものの上での戦闘を表す。この戦場にいるキャラクターは、何らかの行為判定にファンブルした場合〔青春力〕で判定を行う。失敗すると、行動済みになり、速度が0になる。",
  606. "力場。\n展開や魔界の影響を強く受けている戦場。この戦場にいるキャラクターは、ラウンドの終了時に速度0にいると、〔学力〕の判定を行うことができる。成功すると、《アウル》を1点獲得できる。",
  607. "修羅場\n自分たちとは別の撃退士や天魔たちが戦闘を行っていたり、悪意に満ちた第三勢力に囲まれていたりする戦場。この戦場にいるキャラクターは、ラウンドの終了時に速度0にいると、〔政治力〕の判定を行う。失敗すると、《生命力》が1D6点減少する。",
  608. ]
  609. 1 getD6Table(name, table)
  610. end
  611. 1 def getFatalWoundsTable
  612. 1 name = '致命傷表'
  613. 1 table = [
  614. "圧倒的な攻撃が急所をつらぬく。\n行動不能になる。1D6ラウンド後の「ラウンドの終了時」に、まだ戦闘が継続しており、行動不能が回復していなければ、そのキャラクターは死亡する。",
  615. "昏睡し、身体中から血と生きる意志が失われていく。\n行動不能になる。また、この行動不能から回復した後、1D6を振り、ランダムに選んだ変調一つを受ける。",
  616. "大きな傷を負う。行動不能になる。",
  617. "凄まじい一撃に意識を失う。\n《生命力》が0点になり、行動不能になる。",
  618. "一瞬、気を失う。\n行動不能になる。1D6ラウンド後の「ラウンドの終了時」、もしくは、戦闘終了時に《生命力》が1点まで回復する(1D6ラウンドが経過するまでに、すでに《生命力》が1点以上に回復していた場合は、この効果は無効になる)。",
  619. "凄まじい幸運。\nそのシーンに自分に《好意》を持っているキャラクターがいたら、代わりにそのキャラクターがダメージを受けることができる(ダメージを代わりに受けるかどうかは、そのキャラクターを操るプレイヤー、もしくはGMが決定する)。誰もダメージを代わりに受けなかった場合、行動不能になる。",
  620. ]
  621. 1 getD6Table(name, table)
  622. end
  623. 1 def getFumbleTable
  624. 1 name = 'ファンブル表'
  625. 1 table = [
  626. "何もかもむなしくなる。誰かに対する《感情値》を1点減少する。",
  627. "あまりの失敗に心理的変調をきたす。1D6を振ってランダムに変調一つを選び、それを受ける。",
  628. "ポッキリと心が折れる。《アウル》を1点失う。",
  629. "あまりにも酷い大失敗を見られてしまい、周囲のキャラクターからの評価が変わる。自分の周囲に、自分に対して《感情値》を持つキャラクターがいたら、それを反転させる。",
  630. "敵の罠にかかる。自分の周りにいる、自分以外のすべての見方キャラクターは《生命力》を1D6点減少する。",
  631. "アウルが暴走して、大惨事に。自分の《生命力》を2D6点減少する。",
  632. ]
  633. 1 getD6Table(name, table)
  634. end
  635. 1 def getRandomNpcSchoolLife
  636. 2 name = "学生生活関連NPC表"
  637. table = [
  638. 2 [11, "振り直し/任意"],
  639. [12, "大山恵(おおやま・めぐみ):中等部3年0組:P84"],
  640. [13, "黒瀧辰馬(くろたき・たつま):風紀委員長・大学部5年0組:P82"],
  641. [14, "シルヴァリティア・ドーン:大学部1年0組:P83"],
  642. [15, "岸崎蔵人(きしざき・くらんど):大学部5年0組:P84"],
  643. [16, "レミエル・N・V:大学部2年0組:P83"],
  644. [22, "神楽坂茜(かぐらざか・あかね):生徒会会長・高等部2年0組:P82"],
  645. [23, "炎條忍(えんじょう・しのぶ):高等部1年0組:P83"],
  646. [24, "中山寧々美(なかやま・ねねみ):新聞同好会会長・高等部3年0組:P83"],
  647. [25, "恵ヴィヴァルディ(めぐみ・−):大学部2年0組:P83"],
  648. [26, "轟闘吾(とどろき・とうご):高等部3年0組:P84"],
  649. [33, "鬼島武(きじま・たけし):生徒会副会長・大学部1年0組:P82"],
  650. [34, "クリスティーナ・カーティス:大学部1年0組:P83"],
  651. [35, "潮崎紘乃(しおざき・ひろの):依頼斡旋所受付:P84"],
  652. [36, "ライゼ:教師・寮長:P85"],
  653. [44, "大塔寺源九郎(だいとうじ・げんくろう):生徒会書記・高等部3年0組:P82"],
  654. [45, "ストローベレー:用務員:P83"],
  655. [46, "竜崎アリス(りゅうざき・−):オペレーター:P84"],
  656. [55, "大鳥南(おおとり・みなみ):生徒会会計・高等部3年0組:P82"],
  657. [56, "筧鷹政(かけい・たかまさ):OB:P83"],
  658. [66, "振り直し/任意"],
  659. ]
  660. 2 return getRandomNpc(name, table)
  661. end
  662. 1 def getRandomNpcOther
  663. 2 name = "教師・その他NPC表"
  664. table = [
  665. 2 [11, "振り直し/任意"],
  666. [12, "月摘紫蝶(るつみ・しちょう):教師:P84"],
  667. [13, "棄棄(すてき):教師:P84"],
  668. [14, "遠野冴草(とおの・さえぐさ):教師:P84"],
  669. [15, "速水風子(はやみ・ふうこ):教師:P85"],
  670. [16, "アリス・ペンデルトン:教師:P85"],
  671. [22, "宝井正博(たからい・まさひろ):学園長:P82"],
  672. [23, "白田悠里(しろた・ゆうり):教師:P85"],
  673. [24, "常盤楓(ときわ・かえで):教師:P85"],
  674. [25, "ダイナマ伊藤(−・いとう):保健医:P85"],
  675. [26, "小日向千陰(おびなた・ちかげ):教師・司書:P85"],
  676. [33, "ウーネミリア:悪魔:P114"],
  677. [34, "太珀(たいはく):教師:P85"],
  678. [35, "神無月灯(みなづき・あかり):ヴァニタス:P114"],
  679. [36, "キーヨ:ヴァニタス:P114"],
  680. [44, "マッド・ザ・クラウン:悪魔:P114"],
  681. [45, "劉玄盛(りゅう・げんせい):シュトラッサー:P114"],
  682. [46, "厄蔵(やくぞう):シュトラッサー:P114"],
  683. [55, "ギメル・ツァダイ:天使:P114"],
  684. [56, "ナターシャ:シュトラッサー:P114"],
  685. [66, "振り直し/任意"],
  686. ]
  687. 2 return getRandomNpc(name, table)
  688. end
  689. 1 def getRandomNpcDownClassmen
  690. 2 name = "学生図鑑 下級学年表"
  691. table = [
  692. 2 [11, "若菜白兎(わかな・しろう):初等部2年2組:P72"],
  693. [12, "海原満月(かいばら・みづき):初等部4年1組:P66"],
  694. [13, "雫(しずく):初等部4年1組:P60"],
  695. [14, "相馬カズヤ(そうま・−):初等部4年1組:P48"],
  696. [15, "廿九日神無(ひづめ・かんな):初等部4年1組:P62"],
  697. [16, "カイン大澤(−・おおさわ):初等部5年2組:P12"],
  698. [22, "機嶋結(きじま・ゆう):初等部6年2組:P123"],
  699. [23, "静馬源一(しずま・げんいち):初等部6年12組:P78"],
  700. [24, "花菱彪臥(はなびし・ひょうが):中等部1年1組:P53"],
  701. [25, "天菱東希(てんびし・あずき):中等部2年2組:P61"],
  702. [26, "御守陸(みもり・りく):中等部2年2組:P51"],
  703. [33, "西園寺勇(さいおんじ・ゆう):中等部2年3組:P47"],
  704. [34, "九条朔(くじょう・さく):中等部3年1組:P77"],
  705. [35, "柴島華桜璃(くにじま・かおり):中等部3年1組:P48"],
  706. [36, "唐沢完子(からさわ・かんこ):中等部3年2組:P57"],
  707. [44, "雪成藤花(ゆきなり・とうか):中等部3年2組:P53"],
  708. [45, "桐原雅(きりはら・みやび):高等部1年1組:P18"],
  709. [46, "アイリス・L・橋場(−・るなくるす・はしば):高等部1年11組:P79"],
  710. [55, "双星一(そうせい・はじめ):高等部1年120組:P152"],
  711. [56, "影野恭弥(かげの・きょうや):高等部2年2組:P78"],
  712. [66, "振り直し/任意"],
  713. ]
  714. 2 return getRandomNpc(name, table)
  715. end
  716. 1 def getRandomNpcUpperClassmen
  717. 2 name = "学生図鑑 上級学年表"
  718. table = [
  719. 2 [11, "下妻笹緒(しもつま・ささお):高等部2年2組:P117"],
  720. [12, "ファティナ・V・アイゼンブルク(−・フォン・−):高等部2年3組:P110"],
  721. [13, "姫川翔(ひめかわ・しょう):高等部2年5組:P111"],
  722. [14, "イシュタル:高等部2年115組:P152"],
  723. [15, "小田切ルビィ(おだぎり・−):高等部3年4組:P109"],
  724. [16, "大炊御門菫(おおいのみかど・すみれ):高等部3年6組:P112"],
  725. [22, "朱頼天山楓(しゅらい・てんざん・かえで):高等部3年114組:P152"],
  726. [23, "米流是武武(べるぜぶぶ):高等部3年117組:P152"],
  727. [24, "麻生遊夜(あそう・ゆうや):大学部1年1組:P122"],
  728. [25, "フィオナ・ボールドウィン:大学部1年1組:P79"],
  729. [26, "アデル・リーヴィス:大学部1年50組:P152"],
  730. [33, "エルディン:大学部1年50組:P152"],
  731. [34, "斐川幽夜(ひかわ・ももや):大学部2年2組:P57"],
  732. [35, "ミハイル・エッカート:大学部2年4組:P122"],
  733. [36, "阿岳恭司(あたけ・きょうじ):大学部2年9組:P119"],
  734. [44, "アンジェラ・アップルトン:大学部2年9組:P75"],
  735. [45, "アウリーエ・F・ダッチマン(−・フライング・−):大学部3年50組:P152"],
  736. [46, "ジェディファ・エルクラステ:大学部3年50組:P152"],
  737. [55, "有田アリストテレス(ありた・−):大学部4年6組:P69"],
  738. [56, "澄野絣(すみの・かすり):大学部4年6組:P61"],
  739. [66, "振り直し/任意"],
  740. ]
  741. 2 return getRandomNpc(name, table)
  742. end
  743. 1 def getRandomNpc(name, table)
  744. 8 result, number = get_table_by_d66_swap(table)
  745. 8 return "#{name}(#{number}) #{result}"
  746. end
  747. 1 def getUsuallyEncount(level)
  748. 2 name = "日常遭遇表"
  749. table = [
  750. 2 [2, "ブラックシープ(基本p129)×2"],
  751. [3, "イフリート(基本p126)、グリフォン(基本p126)"],
  752. [4, "ファウスト(基本p129)、ワーウルフ(基本p129)"],
  753. [5, "焔の蝶(p99)"],
  754. [6, "デビルキャリアー(p102)、狂信者(p104)"],
  755. [7, "ケルベロス(p99)、百足女(p99)"],
  756. [8, "カプリコーン(p102)×2"],
  757. [9, "邪神怪人(基本p135)"],
  758. [10, "聖少女(基本p127)"],
  759. [11, "業魔(基本p129)、デュアル(基本p126)"],
  760. [12, "ファイアレーベン(p98)×2、ゴーレム(p99)"],
  761. [13, "ブラッドウォーリア(p103)、ブラッドロード(p103)"],
  762. [14, "フェニックス(p99)、ドラゴンゾンビ(p99)"],
  763. [15, "マッドマーマンティス(p102)×2、バンパイアロード(p103)"],
  764. [16, "ドラゴン(p99)×2"],
  765. [17, "風紀委員(p107)、保安委員(p107)×2"],
  766. ]
  767. 2 getEncountTableResult(name, table, level)
  768. end
  769. 1 def getBossEncount(level)
  770. 1 name = "ボスキャラクター遭遇表"
  771. table = [
  772. 1 [2, "剥奪天使(p101)、イフリート(基本p126)×PCと同じ数"],
  773. [3, "没落悪魔(p105)、ブラックシープ(基本p129)×PCと同じ数"],
  774. [4, "技巧派教員(基本p134)、一般人×PCと同じ数"],
  775. [5, "肉体派教員(基本p135)、オペレーター×PCと同じ数"],
  776. [6, "フェニックス(p99)、焔の蝶(p99)×PCと同じ数"],
  777. [7, "美しきバンシー(p103)、デビルキャリアー(p102)×PCと同じ数"],
  778. [8, "ドラゴン(p99)、キラー(基本p126)×PCと同じ数"],
  779. [9, "バンパイアロード(p103)、戦闘員(基本p132)×PCと同じ数"],
  780. [10, "殺戮天使(p101)、下級使徒(p100)×PCと同じ数"],
  781. [11, "小悪魔(p105)、デスストーカー(p102)×PCと同じ数"],
  782. [12, "仙人(基本p127)、サブラヒナイト(基本p126)×PCと同じ数"],
  783. [13, "狂犬(p104)、ワーウルフ(基本p129)×PCと同じ数"],
  784. [14, "下級天使(基本p128)、ケルベロス(p99)×PCと同じ数"],
  785. [15, "誘惑悪魔(p105)、カプリコーン(p102)×PCと同じ数"],
  786. [16, "権天使(基本p128)、百足女(p99)×PCと同じ数"],
  787. [17, "悪魔貴族(基本p131)、ブラッドウォーリア(p103)×PCと同じ数"],
  788. ]
  789. 1 getEncountTableResult(name, table, level)
  790. end
  791. 1 def getEncountTableResult(name, table, level)
  792. 3 dice = @randomizer.roll_once(6)
  793. 3 index = dice + level
  794. 3 text = get_table_by_number(index, table, table.last.last)
  795. 3 then: 0 else: 3 return '' if text.nil?
  796. 3 return "#{name}(#{index}) #{text}"
  797. end
  798. TABLES = {
  799. 1 "EBT" => DiceTable::Table.new(
  800. "お祭り室休憩表",
  801. "2D6",
  802. [
  803. "花火\n「たーまやー!」大きな花火があがって、祭りの雰囲気を盛り上げる。真夜中パートだった場合《好意》を持っているキャラクター一人を選ぶ。選んだキャラクターに対する《感情値》が2点上昇する。真夜中パート以外の場合ゆっくりして《アウル》が1点上昇する。",
  804. "客天魔\n「今日は客として来たんだよ。」天魔が客としてやって来ている!?何もしなければいいけど……。[政治力]で判定を行う。成功すると天魔から称賛され、《アウル》が1点回復する。失敗すると、天魔が暴れて帰ってしまい、[政治力]が2D6点減少する。",
  805. "クタクタ……\n「休ませて……。」祭りの準備にかり出されて、骨の髄まで疲れてしまった。【お金】を1個手に入れるが、「眠気」の変調を受ける。",
  806. "意外な一面\n「あいつ、あんな表情もできたんだ。」お祭りの中で、仲間の意外な一面を知る。PCの中から好きなキャラクターを選ぶ。選んだキャラクターに対する《感情値》の属性を反転する。",
  807. "出店!\nクラブやクラスでお店を出すことになった。[青春力]で判定を行う。判定に成功すると、お店は繁盛して【お金】を1個手に入れる。判定に失敗すると、恥ずかしい目に遭って【アウル】が1点減少する。",
  808. "お祭りの雰囲気\n「ワイワイ、ガヤガヤ。」お祭りだ!つい開放的な気分になって、隣の人を誘ってしまおうかなと思える。好きなPCを一人選ぶ。選んだキャラクターとデートを行う。このデートは選んだキャラクターが行動済みでも行え、デートを行っても行動済みにならない。必ず「友達デート表」を使用すること。",
  809. "対抗レース!\nグラウンドでクラブや委員会を巻き込んだ大レースが始まった!【クラブ】か【委員会】のコミュに所属しているPCは全員、[青春力]で判定を行う。成功すると、《アウル》が1点回復する。さらに、最も達成値が低いキャラクターはMVPとなり、【後輩】を手に入れる。",
  810. "水泳大会!\n「あの子の為に、泳ぐぞ!」大規模な水泳大会!さあ、新記録は出るのか!好きなPCを一人選び、[青春力]で判定を行う。判定に成功すると、選んだPCの自分に対する《感情値》が[判定値の成功度×1]点上昇する。このとき、【水着】もしくは【派手な水着】を持っている場合、この判定の達成値が3点上昇する。",
  811. "応援合戦!\n「フレー!フレー!」応援団に交じって仲間を鼓舞しよう!このパートの間、自分は「行動済み」であってもアシストを行うことができる。",
  812. "怪しげなお店\n「いらっしゃい。……ふふふ。」怪しいクラブが出店しているお店がある。本当に大丈夫か?1D6を振る。1の目が出た場合、【メイド服】を手に入れる。2の目が出た場合、【究極鉛筆】を手に入れる。3の目が出た場合、【みそかれーうどん】を手に入れる。4の目が出た場合、【進化の石】を手に入れる。5の目が出た場合、【牛乳】を手に入れる。6の目が出た場合、【安眠セット】を手に入れる。ただし、ここで手に入れた種別が「食物」のアイテムを使用すると「病気」の変調を受ける。",
  813. "キャンプファイヤーの下で……\nキャンプファイヤーを囲みながら、みんなで踊る。PC全員は、好きなPCを一人選ぶ。PC全員は、選んだPCに対する《感情値》が1点上昇し、属性は《好意》となる。"
  814. ]
  815. ),
  816. "GIT" => DiceTable::Table.new(
  817. "陰謀表",
  818. "2D6",
  819. [
  820. "「お前たちの血を邪神様の生贄に捧げてやる!」\n世界征服同好会の仕掛けた邪悪で陰湿なトラップにひっかかる。PC全員は《生命力》が2D6点減少する。このシナリオに登場する世界征服同好会のキャラクターの名前が分かっている場合、そのキャラクターに対する《感情値》を1点上昇させ、その属性を《敵意》にする。",
  821. "「……キミ、よく見るとかわいいね。ちょっとつきあわない?」\n世界征服同好会の一員からデートを申し込まれる。ランダムにPC一人を選ぶ。そのPCは、このシナリオに登場ソウル正解征服同好会のキャラクター一人と、デートを一回行うことができる。(行動済みにはならない。)",
  822. "「すみません、少し道を尋ねたいのですが……。」\n謎の老婆に道を尋ねられる。PCの代表者は1D6を振ること。奇数だと老婆に変装した世界征服同好会の刺客だった。PC全員は《生命力》が1D6点減少し、「バカ」の変調を受ける。偶数だと助けた老人から感謝される。【焼きそばパン】一個か【タリスマン】一個を獲得する。",
  823. "「あなたは、だんだん眠くなるぅ〜。」\n世界征服同好会の催眠に合う。PC全員が受けている変調をすべて回復し、「眠気」の変調を受ける。",
  824. "「ねぇねぇ、あの人たちって……。」\n世界征服同好会が、PCたちの悪い噂をばらまく。このパートに判定を行う場合、[学力]以外の能力値で行う判定は、ファンブル率が3上昇する。",
  825. "「ねぇねぇ、ボクともっと遊んでよ。」\n世界征服同好会が、様々な妨害工作を行っている。このパートに行う判定は、ファンブル率が1上昇する。",
  826. "「ねぇねぇ、あの人って……。」\nPCたちの一人に世界征服同好会の一員であるという嫌疑がかけられる。ランダムにPC一人を選ぶ。そのPCに対して《好意》を持っているPCがいたら、そのPCは[政治力]で判定を行う。失敗するとNPCのそのキャラクターに対する《好意》が《敵意》に変わる。",
  827. "「ふふふ、僕の言う未来に興味はないかい?」\n世界征服同好会の催眠に合う。PC全員の《アウル》の現在値を1にする。",
  828. "「これ以上我々の邪魔をすると死ぬことになるぞ。」\n物陰から世界征服同好会の構成員が襲い掛かってきた。PCの代表者は[青春力]の判定を行う。成功すると、襲いかかってきた構成員を返り討ちにできる。GMは決戦フェイズに登場するエネミーから一体を選び、《生命力》を3D6点減少させること。失敗すると、戦いに敗れてしまう。PC全員は、《生命力》が1D6点減少し「恐怖」の変調を受ける。",
  829. "「ふふふふふ、ここで大人しくしておけ。」\n世界征服同好会に監禁されてしまう。PCの代表者は[学力]の判定を行う。失敗すると、プレイスの中から好きなものを一つ選ぶ。PC全員、そのパートは、そのプレイスで休憩する以外の行動を行えなくなる。",
  830. "「我々のファミリーに近づく者には消えてもらおう。」\n世界征服同好会の仕掛けた周到で悪逆なトラップにひっかかる。PC全員はゲームマスターの選んだ変調を一つ受ける。(PCごとにばらばらの変調を選んでもよい)。このシナリオに登場する世界征服同好会のキャラクターの名前が分かっている場合、そのキャラクターに対する《感情値》を1点上昇させ、その属性を《敵意》にする。"
  831. ]
  832. ),
  833. "HBT" => DiceTable::Table.new(
  834. "温泉休憩表",
  835. "2D6",
  836. [
  837. "風紀委員の巡回!\n\"「そこ、何やってる!」風紀委員に見つかった。現在が授業パートであればこっぴどく叱られる。[政治力]で判定を行う。失敗すると、次のパートは行動できない。授業パート以外であれば、心身ともにリフレッシュ。《アウル》が1点回復する。",
  838. "サウナで激闘!\n「……あいつに負けるわけには。」サウナでがまん比べが始ってしまう。[政治力]で判定を行う。成功すると《アウル》1点を獲得する。失敗すると、「病気」の変調を受ける。",
  839. "湯上りの一杯\n\"「お風呂の後はこれだよな!」[政治力]で判定を行う。成功すると、変調をすべて回復することができる。",
  840. "あれ?服が……\n「あれ?何だこれ?」自分の着替えを入れたはずのロッカーを開けてみると、服が消えて、別の何かが……。「防具」を装備していたら、その中から一つを選び、それを消費する。そして消費したアイテムの代わりに「初期アイテム決定表(基本P43)」を一度使用して、ランダムに一つのアイテムを獲得する。",
  841. "偶然の出会い\n「あれ?来てたんだ。」知り合いと偶然出会う。好きなキャラクター一人を選び、[青春力]の判定を行う。成功すると、そのキャラクターとデートを一度行うことができる。",
  842. "いいお湯♪\n「ふう。体の芯から温まるぅ。」疲れがとれていく。《生命力》が1D6点、《アウル》が1点回復する。",
  843. "転倒!\n「はわわわわッ!」洗い場で滑って転びそうになる。[学力]で判定を行う。失敗すると、獲得していた「手がかり」を一つ失う。(「手がかり」の活用が行えなくなるだけで、情報を忘れるわけではない。)",
  844. "命の洗濯\n「……。」お風呂に入りながら、今週の出来事を振り返る。失敗を次に活かさないと……。もしも、このセッションの間に一度以上判定に失敗していたら、《アウル》の限界値が1点上昇する。",
  845. "湯あたり\n「うう。のぼせちゃった。」お風呂に長時間入ってのぼせてしまった。1D6点のダメージを受けるか、次のパート行動しないか、どちらかを選ぶ。",
  846. "美容効果\nお肌がツルツルピカピカ!そのセッションの間、[青春力]の判定の達成値が1点上昇する。",
  847. "混浴ッッ!?\n湯船に入ってみると、そこには異性の姿が……ええッ!?男湯と女湯間違えたッ!?好きな異性のキャラクターを1人選ぶ。そのキャラクターの自分に対する《達成値》が2点上昇する。その後、[青春力]で判定を行う。失敗すると「バカ」の変調を受ける。"
  848. ]
  849. ),
  850. "HT" => DiceTable::Table.new(
  851. "ロウ表",
  852. "2D6",
  853. [
  854. "「たまには釣りにでも行くか」「釣り人表」を振る。",
  855. "「汚い下着があったので没収!」【インナー】(基本p104)を取得し《アウル》を1点取得する。ただし、誰のものかはPCの中からランダムで決定する。",
  856. "「街をきれいに!……ふー、心がきれいになったなあ!」ボランティア活動をしよう!プレイスの中から1つ選び、その表を振る。その後、生命力を1D6点回復する。",
  857. "「いやー、いいことを言ったなあ」お説教をする。あなた以外のPCを一人選ぶ。選ばれたPCとあなたはカオスレートを+1する。",
  858. "ついつい人の恋愛事情に口出ししてしまう。自分以外の任意のPC(できれば異性)2人をデートさせる。この表によるデートは行動を消費しない。",
  859. "身近にいるカオスなやつがむかついてしょうがない。理由もなく殴ってすべてのカオスレートが-2以下のPCに2D6点のダメージを与える。成功度を1として扱い好きな能力値でガードが可能。",
  860. "「な、なんでもないはずなのに!」叱っていたアイツのことが気になってきた……。もっともカオスレートが低い異性のキャラクターに対する《感情値》が2点上昇する。",
  861. "ネット上で情報について検索していたら、いつの間にかネット上で喧嘩していた。つい熱くなってしまう。「バカ」の変調を受けるが、好きな感情を1つだけ公開することができる。",
  862. "ありがたい高級なツボを手近にいたPCに売りつける。ランダムに【お金】を持つあなた以外のPCを選ぶ。そのキャラクターは【お金】をすべて消費し、【タリスマン】(基本p107)を入手するが、あなたは「孤独」を受ける。【お金】がなかった場合、舌打ちだけする。",
  863. "「欲望には勝てなかったよ……」ちょっとした誘惑から悪堕ちして、露出度の高い格好になるしやたらと黒と漢字を好むようになった。カオスレートを-5する。【タバコ】(基本p160)と【お酒】(基本p160)を1個ずつ獲得する。",
  864. "ロウとカオスの境界線なんて曖昧なものなのかもしれない。「カオス表」を振る。"
  865. ]
  866. ),
  867. "IT" => DiceTable::Table.new(
  868. "釣り人表",
  869. "1D6",
  870. [
  871. "「良い物が釣れたぞ!」価格3以下のアイテムを1つ選んで入手する。",
  872. "足を釣った。行動済でなかった場合、行動済みになる。",
  873. "下着を釣ってしまった。【インナー】(基本p104)を入手する。ただし、誰のものかはPCの中からランダムで決定する。",
  874. "「太公望になった気分だ」釣りをしながら、政治を語る。カオスレートを+1もしくは-1できる。",
  875. "「大漁大漁!」お魚を換金して【お金】を1個入手する。",
  876. "ついサメを釣ってしまった。【キラー】(基本p126)と戦闘を行う。この戦闘はイベントシーン扱いとし、撤退できない。"
  877. ]
  878. ),
  879. "JH" => DiceTable::Table.new(
  880. "授業ハプニング表",
  881. "2D6",
  882. [
  883. "授業中に突然テロリストが侵入してくる。「日常遭遇表(p97)」を使ってエネミーを決定する。そのエネミーと、この授業判定を行ったキャラクターは戦闘を行う。",
  884. "もうすこしがんばりましょう。先生からのプレゼント。もし、この授業判定に失敗していたら、この表を使用したキャラクターは【参考書】(基本p107)を一つ獲得する。",
  885. "居眠りしてたらリフレッシュ!この表を使用したキャラクターは、《生命力》を1D6点回復する。",
  886. "先生からお使いを頼まれる。この表を利用したキャラクターは、「図書館」(基本p92)の「図書館休憩表」を使用する。",
  887. "アウルが暴走して事故発生!この表を使用したキャラクターは《生命力》を1D6点減少する。",
  888. "授業中に生徒同士で口論になる。この授業判定を行ったキャラクターの中に、この表を使用したキャラクターに対して《好意》を持っていたキャラクターがいたら、その属性を《敵意》にする。",
  889. "先生から課題をもらう。この表を使用したキャラクターは、次に[学力]で判定に成功するまで、この授業の□にチェックを入れることができない(チェックを入れることができないような場合は、特に効果はない)。",
  890. "先生は受講態度が気にくわなかったようだ。なぜか廊下に立たされる。この表を使用したキャラクターは、1D6を振って、ランダムに変調一つを選び、それを受ける。",
  891. "ちょっとだけ自習になる。この授業判定に参加したキャラクター全員は、「教室」(基本p87)の「教室休憩表」を一度ずつ使用する。",
  892. "を?こんなところにパンが落ちてる。この表を使用したキャラクターは【焼きそばパン】(基本p106)を一つ獲得する。この【焼きそばパン】を使用した時1D6を振る。1が出ると、通常の【焼きそばパン】の効果の代わりに《生命力》が1点減少する。",
  893. "先生はみんなの授業態度に大いに満足したようだ。授業判定の成否や授業レベル、授業の種類に関わらず、授業判定に参加したキャラクター全員は、この曜日の授業の□にチェックを入れる。"
  894. ]
  895. ),
  896. "KT" => DiceTable::Table.new(
  897. "カオス表",
  898. "2D6",
  899. [
  900. "「たまには釣りにでも行くか」「釣り人表」を振る。",
  901. "悪いとわかっていたがつい下着を手に取ってしまう。【インナー】(基本p104)を取得し《アウル》を1点獲得する。ただし、誰のものかはPCの中からランダムで決定する。",
  902. "「ヒャッハー!」カオスに染まってとりあえず手近なところに襲撃を行う。プレイスの中から1つを選び、その表を振る。その後【お金】を1個入手し、カオスレートを-1する。",
  903. "「なあ、ちょっとやってみないか。ちょっとでいいから、な?」ワルの道に勧誘する。あなた以外のPCを一人選ぶ。選ばれたPCとあなたはカオスレートを-1する。",
  904. "「横恋慕をしてナンボ」それがカオスの恋愛だ。一度でもデートをしたPCの片方に対してデートを行う。デートしたPCが居ない場合、任意のPCに対してデートを行う。この表によるデートは行動を消費しない。",
  905. "身近にいるロウなやつがムカついてしょうがない。理由もなく殴ってすべてのカオスレートが+2以上のPCに2D6点のダメージを与える。この攻撃は成功度を1として扱い、好きな能力値でガード可能。",
  906. "「だるい……休もう……」あなたの《生命力》を2D6点回復する。ただし、「眠気」の変調を受ける。",
  907. "ゲームセンターに行ってストレスを発散!……できればいいな。「青春力」の判定を行う。成功すると、《アウル》を2個獲得する。失敗するとムキになって【お金】を1個失う上に「バカ」の変調を受ける。",
  908. "「せっかくだから覗きをしよう。フヘへ……」「プール休憩表」もしくは「温泉休憩表(p78)を任意のPCに振らせ、その効果をPCに適応させる。その後あなたのそのPCに対する《感情値》を2点上昇させる。",
  909. "捨て猫を披露。あなたのカオスレートが+5され、あなたに対する《感情値》の属性がすべて反転する。また【後輩】(基本p106)を獲得する。",
  910. "ロウとカオスの境界線なんて曖昧なものなのかもしれない。「ロウ表」を振る。"
  911. ]
  912. ),
  913. "NA" => DiceTable::Table.new(
  914. "新初期アイテム決定表",
  915. "2D6",
  916. [
  917. "従 者 p89",
  918. "菓子折り p88",
  919. "ホイッスル p89",
  920. "おせっかいな友人 p89",
  921. "釣り竿 p89",
  922. "牛 乳 p88",
  923. "究極六角鉛筆 p90",
  924. "使い捨てカメラ p89",
  925. "メイド服 p89",
  926. "マスコットストラップ p89",
  927. "秘薬の小瓶 p88"
  928. ]
  929. ),
  930. "NT" => DiceTable::Table.new(
  931. "ニュートラル表",
  932. "1D6",
  933. [
  934. "「善とか悪とか、全部煩わしくなってきた」カオスレートが+2以上もしくは2以下のPCがいる場合、そのキャラクター全てを理由もなく殴りつける。。殴りつけられたPCに2D6点のダメージを与える。この攻撃は成功度を1として扱い、好きな能力値でガード可能。",
  935. "「危ない!」電車に轢かれそうな子供が!?【生命力】を1D6点失うものの、助けて感謝される。いいことをすると気持ちいいなあ。カオスレート+1。",
  936. "心のバランスを保つため、釣りでもしよう。「釣り人表」を振る。",
  937. "「どうしよう」落し物の財布を拾っちゃった……。ネコババすると、カオスレートが-3されて【お金】を2つ入手。ちゃんと交番に届けるとカオスレートが+1されて、お礼に【お金】を1つ入手。",
  938. "急に興奮する。「ロウ表」もしくは「カオス表」のどちらか好きな方を振る。",
  939. "人に影響される。すべてのPCのカオスレートを合計し、+1以上だった場合、あなたのカオスレートを+2する。-1以下だった場合、あなたのカオスレートを-2する。0だった場合、特に何も起こらない。"
  940. ]
  941. ),
  942. "OJ1" => DiceTable::Table.new(
  943. "音楽ジャンル決定表A",
  944. "1D6",
  945. [
  946. "さわやかな",
  947. "ちょっと大人な",
  948. "正統派",
  949. "初恋色の",
  950. "女の子らしい",
  951. "カオス全開☆"
  952. ]
  953. ),
  954. "OJ2" => DiceTable::Table.new(
  955. "音楽ジャンル決定表B",
  956. "1D6",
  957. [
  958. "アイドルポップス",
  959. "ロックチューン",
  960. "ラブソング",
  961. "バラード",
  962. "テクノポップ",
  963. "電波ソング"
  964. ]
  965. ),
  966. "TBT" => DiceTable::Table.new(
  967. "修学旅行休憩表",
  968. "2D6",
  969. [
  970. "見回り先生の巡回!\n「そこ、何やってる!」見回りの先生に見つかった。現在真夜中パートであれば、こっぴどく叱られる。[政治力]で判断を行う。失敗すると、次のパートは行動できない。真夜中パート以外であれば、心身ともにリフレッシュ。《アウル》が1点回復する。",
  971. "自然災害\n修学旅行先で自然災害に遭ってしまい、観光しようにもできない。仕方ないのでホテルでゆっくりしよう。《生命力》を2D6点回復する。",
  972. "地元の天魔!\n「見かけない撃退士だな。」「初めて見る天魔だ。」好きな能力値で判定を行う。判定に成功すると、このシナリオで登場する天魔の種類をすべてGMから教えてもらえる。失敗すると《生命力》が1D6点減少する。",
  973. "二人で迷子\n「あれれ?こっちの道でよかったのかな?」二人ではぐれてしまう。PCの中から好きなキャラクターを1人選ぶ。自分の選んだキャラクターに対する《感情値》が1点上昇し、属性が《敵意》になる。",
  974. "ホームシック\n不意に、久遠ヶ原学園が懐かしくなっていしまう。「孤独」の変調を受ける。",
  975. "歴史的観光地\n歴史のある観光地を見て回り、自分の五感で知識を蓄える。[学力]で判定を行う。西欧すると、自分の修得している授業から好きなものを一つ選び、□にチェックを入れる。",
  976. "お土産屋\n「旅のお土産にお一ついかがですか?」お土産屋でいろいろなものをチェックする!役立つものもあるかも?[青春力]で判定を行う。成功すると、分類が[一般]、価値が2以下の好きなアイテムを一個獲得する。失敗すると、木刀やペナントなど役に立たないものを買い込んでしまう。【お金】を1個失う。",
  977. "名産品\nその他の名産品を食べて舌鼓を打つ。おいしい!《アウル》が1点回復し、「空腹」の変調が回復する。",
  978. "地元の学校\n「よろしゅーに。」「なかようせんとあかんよ。」地元の学校と共同授業だ。これは負けていられない。[学力]で判定を行う。判定に成功すると、地元の生徒からの《好意》が2点上昇し、「バカ」の変調が回復する。失敗すると、「バカ」の変調を受ける。",
  979. "枕投げ!\nやっぱり修学旅行といえば枕投げでしょ!PCの中から好きなキャラクターを一人選ぶ。[青春力]で判定を行う。成功すると、そのキャラクターは《生命力》が1D6点減少し、そのキャラクターの自分に対する《感情値》が2点上昇する。失敗すると、自分の《生命力》が1D6点減少し、そのキャラクターに対する《感情値》が2点上昇する。",
  980. "好きな人語り!\n「ねえねえ、この際だからハッキリ言っちゃおうよ。」修学旅行での楽しみ、それがこの好きな人を語り合う時間だ。真夜中パートならば、PC全員はそれぞれ《好意》が最も高いPCを一人発表する。発表したPCは、発表されたPCに対する《感情値》が2点上昇する。真夜中パート以外であれば、よく眠ってリフレッシュ。《アウル》が1点回復する。"
  981. ]
  982. ),
  983. "UBT" => DiceTable::Table.new(
  984. "潜入調査休憩表",
  985. "2D6",
  986. [
  987. "風紀委員の巡回!\n「そこ、何をやっている!」他校の風紀委員に見つかった。現在が授業パートであれば、こっぴどく叱られる。[政治力]で判定を行う。失敗すると、次のパートは行動できない。授業パート以外であれば、心身ともにリフレッシュ。《アウル》が1点回復する。",
  988. "協力者\n「キミが、久遠ヶ原学園から来た子だね。」正体を知っている協力者との密会。次に行う調査判定が2点上昇する。",
  989. "変装中\n「どう?似合ってる?」変装をする為に、支援物資が届いていた。【メガネ】か【ジャージ】の内、好きな方を獲得する。",
  990. "不良に絡まれる\n「おい、テメェ最近目立ってるんだってな。」どうやら、他校の不良生徒に絡まれてしまったようだ。穏便に解決しなければ。【お金】か【タバコ】か【お酒】があれば、1個消費する。消費できなかった場合、殴られて《生命力》が1D6点減少する。",
  991. "教師からの注意\n「キミ、ちゃんとしてくれないと困るよ。」規律をいつの間にか破っていたらしい。教師から注意を受けて、《アウル》が1点減少する。",
  992. "一般授業\n「で、あるからして……。」一般的な授業を受ける。これが外の世界の普通か……。[学力]で判定を行う。成功すると【一般授業】か【交流授業】の□にチェックを入れる。どちらもない場合、スケジュールの好きな欄に【一般授業】を入れられる。",
  993. "お昼\n「はい、今日のメニューはこれ。」少々混むことはあるが、問題なく普通に食べることができる。コメントし辛い味で、なんだか物足りないような気もするけど……。《生命力》を1D6点回復する。",
  994. "おっかけ\n「びびびっと来ました!」どうしても目立ってしまう自分に、おっかけができてしまう。やりにくい……。おっかけとデートを行うことを選べる。デートを行わなかった場合、「孤独」の変調を受ける。",
  995. "うっかり\n「え、なにあれ……?」いつもの調子で、学校の中で能力を使いそうになる。[政治力]で判定を行う。成功すると、うまく説得して協力者にできる。【おせっかいな友人】を獲得する。失敗すると、なんとか誤魔化せたが視線が痛い。撃退士以外の生徒の自分に対する《感情値》が2点上昇し、その属性は《敵意》となる。",
  996. "襲撃\n「きゃあー!」一般生徒が天魔に襲われている!バレないように助けないと……。好きな能力値で判定を行う。成功すると、うまくバレずに助け出せる。撃退士以外の生徒に対する《感情値》が3点上昇し、その属性は《好意》となる。失敗すると、助けることには成功したが、傷を負ってしまう。《生命力》が2D6点減少する。",
  997. "疑い\n「キミって、ひょっとすると……。」勘のいい生徒から、本格的に疑われてしまう。[政治力]で判定を行う。成功すると、疑いを晴らすことができた上に、重要な情報をくれる。GMが選択した手がかり一つの情報を公開する。失敗すると、疑いの視線が学校中から向けられてしまう。《アウル》を2点減少する。"
  998. ]
  999. ),
  1000. "UT1" => DiceTable::D66Table.new(
  1001. "ユニット名決定表1A",
  1002. D66SortType::ASC,
  1003. {
  1004. 11 => "白い",
  1005. 12 => "月の",
  1006. 13 => "私は",
  1007. 14 => "虹色の",
  1008. 15 => "放課後",
  1009. 16 => "はじめての",
  1010. 22 => "乙女の",
  1011. 23 => "ピンクの",
  1012. 24 => "魔法の",
  1013. 25 => "蒼い",
  1014. 26 => "恋の",
  1015. 33 => "ときめき",
  1016. 34 => "太陽の",
  1017. 35 => "燃えよ",
  1018. 36 => "雨の",
  1019. 44 => "星の",
  1020. 45 => "君に",
  1021. 46 => "思い出の",
  1022. 55 => "都会の",
  1023. 56 => "やさしい",
  1024. 66 => "黒い"
  1025. }
  1026. ),
  1027. "UT2" => DiceTable::D66Table.new(
  1028. "ユニット名決定表1B",
  1029. D66SortType::ASC,
  1030. {
  1031. 11 => "革命",
  1032. 12 => "エージェント",
  1033. 13 => "アリス",
  1034. 14 => "自転車",
  1035. 15 => "忍者",
  1036. 16 => "予知夢",
  1037. 22 => "リボン",
  1038. 23 => "メロディー",
  1039. 24 => "バースデイ",
  1040. 25 => "チョコレート",
  1041. 26 => "プレゼント",
  1042. 33 => "カオス",
  1043. 34 => "つばさ",
  1044. 35 => "夏",
  1045. 36 => "ココロ",
  1046. 44 => "ジェラシー",
  1047. 45 => "朝ご飯",
  1048. 46 => "保健室",
  1049. 55 => "祈り",
  1050. 56 => "迷宮",
  1051. 66 => "久遠ヶ原学園"
  1052. }
  1053. ),
  1054. "UT3" => DiceTable::D66Table.new(
  1055. "ユニット名決定表2A",
  1056. D66SortType::ASC,
  1057. {
  1058. 11 => "堕天使",
  1059. 12 => "ラヴクラフト",
  1060. 13 => "セレブリティ",
  1061. 14 => "スターダスト",
  1062. 15 => "ロリポップ",
  1063. 16 => "ファースト",
  1064. 22 => "ストロベリー",
  1065. 23 => "シャイニー",
  1066. 24 => "ドリーム",
  1067. 25 => "ヴァンパイア",
  1068. 26 => "シンデレラ",
  1069. 33 => "スウィート",
  1070. 34 => "ウィッチ",
  1071. 35 => "フラワー",
  1072. 36 => "オレンジ",
  1073. 44 => "ダイアモンド",
  1074. 45 => "モノクロ",
  1075. 46 => "バレンタイン",
  1076. 55 => "スタイリッシュ",
  1077. 56 => "コンクリート",
  1078. 66 => "ニンジャ"
  1079. }
  1080. ),
  1081. "UT4" => DiceTable::D66Table.new(
  1082. "ユニット名決定表2B",
  1083. D66SortType::ASC,
  1084. {
  1085. 11 => "スレイヤー",
  1086. 12 => "ファイター",
  1087. 13 => "セッション",
  1088. 14 => "ドーナツ",
  1089. 15 => "ワルツ",
  1090. 16 => "ティアラ",
  1091. 22 => "ガール",
  1092. 23 => "スカイ",
  1093. 24 => "キス",
  1094. 25 => "シティ",
  1095. 26 => "ステージ",
  1096. 33 => "ラブ",
  1097. 34 => "ロマンス",
  1098. 35 => "ノート",
  1099. 36 => "ショコラ",
  1100. 44 => "プリンセス",
  1101. 45 => "キャンディ",
  1102. 46 => "ハニー",
  1103. 55 => "ハンター",
  1104. 56 => "ディスコ",
  1105. 66 => "ブルー"
  1106. }
  1107. ),
  1108. }.freeze
  1109. 1 register_prefix(
  1110. 'EL',
  1111. 'DATE', 'FDATE', 'ODATE', 'MDATE',
  1112. 'RBT', 'SBT', 'BBT', 'CBT', 'DBT', 'IBT', 'FBT', 'LBT', 'PBT', 'NBT', 'ABT', 'VBT', 'GBT', 'HBT',
  1113. 'BFT', 'FWT', 'FT',
  1114. 'SRT', 'ORT', 'DRT', 'URT',
  1115. 'NJ', 'BS', TABLES.keys
  1116. )
  1117. end
  1118. end
  1119. end

lib/bcdice/game_system/EmbryoMachine.rb

95.24% lines covered

77.27% branches covered

105 relevant lines. 100 lines covered and 5 lines missed.
44 total branches, 34 branches covered and 10 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class EmbryoMachine < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'EmbryoMachine'
  7. # ゲームシステム名
  8. 1 NAME = 'エムブリオマシンRPG'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'えむふりおましんRPG'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定ロール(EMt+m@c#f)
  14.  目標値t、修正値m、クリティカル値c(省略時は20)、ファンブル値f(省略時は2)で攻撃判定を行います。
  15.  命中した場合は命中レベルと命中部位も自動出力します。
  16.  Rコマンドに読み替えされます。
  17. ・各種表
  18.  ・命中部位表 HLT
  19.  ・白兵攻撃ファンブル表 MFT
  20.  ・射撃攻撃ファンブル表 SFT
  21. INFO_MESSAGE_TEXT
  22. 1 register_prefix('EM', 'HLT', 'MFT', 'SFT', '2R10')
  23. 1 def initialize(command)
  24. 133 super(command)
  25. 133 @sort_add_dice = true
  26. end
  27. 1 def replace_text(string)
  28. 120 string
  29. 40 .gsub(/EM(\d+)([+-][+\-\d]+)(@(\d+))(\#(\d+))/i) { "2R10#{Regexp.last_match(2)}>=#{Regexp.last_match(1)}[#{Regexp.last_match(4)},#{Regexp.last_match(6)}]" }
  30. 10 .gsub(/EM(\d+)([+-][+\-\d]+)(\#(\d+))/i) { "2R10#{Regexp.last_match(2)}>=#{Regexp.last_match(1)}[20,#{Regexp.last_match(4)}]" }
  31. 10 .gsub(/EM(\d+)([+-][+\-\d]+)(@(\d+))/i) { "2R10#{Regexp.last_match(2)}>=#{Regexp.last_match(1)}[#{Regexp.last_match(4)},2]" }
  32. 20 .gsub(/EM(\d+)([+-][+\-\d]+)/i) { "2R10#{Regexp.last_match(2)}>=#{Regexp.last_match(1)}[20,2]" }
  33. .gsub(/EM(\d+)(@(\d+))(\#(\d+))/i) { "2R10>=#{Regexp.last_match(1)}[#{Regexp.last_match(3)},#{Regexp.last_match(5)}]" }
  34. .gsub(/EM(\d+)(\#(\d+))/i) { "2R10>=#{Regexp.last_match(1)}[20,#{Regexp.last_match(3)}]" }
  35. .gsub(/EM(\d+)(@(\d+))/i) { "2R10>=#{Regexp.last_match(1)}[#{Regexp.last_match(3)},2]" }
  36. 10 .gsub(/EM(\d+)/i) { "2R10>=#{Regexp.last_match(1)}[20,2]" }
  37. end
  38. # ゲーム別成功度判定(nD10)
  39. 1 def result_nd10(total, dice_total, _dice_list, cmp_op, target)
  40. 13 else: 13 then: 0 return nil unless cmp_op == :>=
  41. 13 then: 2 if dice_total <= 2
  42. 2 else: 11 Result.fumble("ファンブル")
  43. 11 then: 4 elsif dice_total >= 20
  44. 4 else: 7 Result.critical("クリティカル")
  45. 7 then: 1 elsif target == "?"
  46. 1 else: 6 Result.nothing
  47. 6 then: 3 elsif total >= target
  48. 3 Result.success("成功")
  49. else: 3 else
  50. 3 Result.failure("失敗")
  51. end
  52. end
  53. 1 def checkRoll(string)
  54. 120 string = replace_text(string)
  55. 120 else: 90 then: 30 return nil unless /(^|\s)S?(2[rR]10([+\-\d]+)?([>=]+(\d+))(\[(\d+),(\d+)\]))(\s|$)/i =~ string
  56. 90 string = Regexp.last_match(2)
  57. 90 diff = 0
  58. 90 crit = 20
  59. 90 fumble = 2
  60. 90 mod = 0
  61. 90 modText = Regexp.last_match(3)
  62. 90 then: 90 else: 0 diff = Regexp.last_match(5).to_i if Regexp.last_match(5)
  63. 90 then: 90 else: 0 crit = Regexp.last_match(7).to_i if Regexp.last_match(7)
  64. 90 then: 90 else: 0 fumble = Regexp.last_match(8).to_i if Regexp.last_match(8)
  65. 90 then: 80 else: 10 mod = ArithmeticEvaluator.eval(modText) if modText
  66. 90 dice_arr = @randomizer.roll_barabara(2, 10).sort
  67. 90 dice_now = dice_arr.sum()
  68. 90 dice_str = dice_arr.join(",")
  69. 90 dice_loc = @randomizer.roll_sum(2, 10)
  70. 90 big_dice = dice_arr[1]
  71. 90 output = "#{dice_now}[#{dice_str}]"
  72. 90 total_n = dice_now + mod
  73. 90 then: 70 if mod > 0
  74. 70 else: 20 output += "+#{mod}"
  75. 20 then: 10 else: 10 elsif mod < 0
  76. 10 output += mod.to_s
  77. end
  78. 90 then: 90 if output =~ /[^\d\[\]]+/
  79. 90 output = "(#{string}) > #{output} > #{total_n}"
  80. else: 0 else
  81. output = "(#{string}) > #{output}"
  82. end
  83. # 成功度判定
  84. 90 then: 1 if dice_now <= fumble
  85. 1 else: 89 output += " > ファンブル"
  86. 89 then: 0 elsif dice_now >= crit
  87. else: 89 output += " > クリティカル > " + get_hit_level_table(big_dice) + "(ダメージ+10) > [#{dice_loc}]#{get_hit_location_table(dice_loc)}"
  88. 89 then: 84 elsif total_n >= diff
  89. 84 output += " > 成功 > " + get_hit_level_table(big_dice) + " > [#{dice_loc}]#{get_hit_location_table(dice_loc)}"
  90. else: 5 else
  91. 5 output += " > 失敗"
  92. end
  93. 90 return output
  94. end
  95. 1 def eval_game_system_specific_command(command)
  96. 120 debug("eval_game_system_specific_command command", command)
  97. 120 then: 90 else: 30 if (result = checkRoll(command))
  98. 90 return result
  99. end
  100. 30 output = '1'
  101. 30 type = ""
  102. 30 number = 0
  103. 30 else: 0 case command
  104. when: 10 when /HLT/i
  105. 10 type = '命中部位'
  106. 10 number = @randomizer.roll_sum(2, 10)
  107. 10 output = get_hit_location_table(number)
  108. when: 10 when /SFT/i
  109. 10 type = '射撃ファンブル'
  110. 10 number = @randomizer.roll_sum(2, 10)
  111. 10 output = get_shoot_fumble_table(number)
  112. when: 10 when /MFT/i
  113. 10 type = '白兵ファンブル'
  114. 10 number = @randomizer.roll_sum(2, 10)
  115. 10 output = get_melee_fumble_table(number)
  116. end
  117. 30 then: 30 else: 0 if output != '1'
  118. 30 output = "#{type}表(#{number}) > #{output}"
  119. end
  120. 30 return output
  121. end
  122. # ** 命中部位表
  123. 1 def get_hit_location_table(num)
  124. table = [
  125. 94 [4, '頭'],
  126. [7, '左脚'],
  127. [9, '左腕'],
  128. [12, '胴'],
  129. [14, '右腕'],
  130. [17, '右脚'],
  131. [20, '頭'],
  132. ]
  133. 94 return get_table_by_number(num, table)
  134. end
  135. # ** ファンブル表
  136. 1 def get_shoot_fumble_table(num) # 射撃攻撃ファンブル表
  137. 10 output = '1'
  138. 10 table = [
  139. '暴発した。使用した射撃武器が搭載されている部位に命中レベルAで命中する。',
  140. 'あまりに無様な誤射をした。パイロットの精神的負傷が2段階上昇する。',
  141. '誤射をした。自機に最も近い味方機体に命中レベルAで命中する。',
  142. '誤射をした。対象に最も近い味方機体に命中レベルAで命中する。',
  143. '武装が暴発した。使用した射撃武器が破損する。ダメージは発生しない。',
  144. '転倒した。次のセグメントのアクションが待機に変更される。',
  145. '弾詰まりを起こした。使用した射撃武器は戦闘終了まで使用できなくなる。',
  146. '砲身が大きく歪んだ。使用した射撃武器による射撃攻撃の命中値が戦闘終了まで-3される。',
  147. '熱量が激しく増大した。使用した射撃武器の消費弾薬が戦闘終了まで+3される。',
  148. '暴発した。使用した射撃武器が搭載されている部位に命中レベルBで命中する。',
  149. '弾薬が劣化した。使用した射撃武器の全てのダメージが戦闘終了まで-2される。',
  150. '無様な誤射をした。パイロットの精神的負傷が1段階上昇する。',
  151. '誤射をした。対象に最も近い味方機体に命中レベルBで命中する。',
  152. '誤射をした。自機に最も近い味方機体に命中レベルBで命中する。',
  153. '砲身が歪んだ。使用した射撃武器による射撃攻撃の命中値が戦闘終了まで-2される。',
  154. '熱量が増大した。使用した射撃武器の消費弾薬が戦闘終了まで+2される。',
  155. '砲身がわずかに歪んだ。使用した射撃武器による射撃攻撃の命中値が戦闘終了まで-1される。',
  156. '熱量がやや増大した。使用した射撃武器の消費弾薬が戦闘終了まで+1される。',
  157. '何も起きなかった。',
  158. ]
  159. 10 dc = 2
  160. 10 then: 10 else: 0 output = table[num - dc] if table[num - dc]
  161. 10 return output
  162. end
  163. 1 def get_melee_fumble_table(num) # 白兵攻撃ファンブル表
  164. 10 output = '1'
  165. 10 table = [
  166. '大振りしすぎた。使用した白兵武器が搭載されている部位の反対の部位(右腕に搭載されているなら左側)に命中レベルAで命中する。',
  167. '激しく頭を打った。パイロットの肉体的負傷が2段階上昇する。',
  168. '過負荷で部位が爆発した。使用した白兵武器が搭載されている部位が全壊する。ダメージは発生せず、搭載されている武装も破損しない。',
  169. '大振りしすぎた。使用した白兵武器が搭載されている部位の反対の部位(右腕に搭載されているなら左側)に命中レベルBで命中する。',
  170. '武装が爆発した。使用した白兵武器が破損する。ダメージは発生しない。',
  171. '部分的に機能停止した。使用した白兵武器は戦闘終了まで使用できなくなる。',
  172. '転倒した。次のセグメントのアクションが待機に変更される。',
  173. '激しい刃こぼれを起こした。使用した白兵武器の全てのダメージが戦闘終了まで-3される。',
  174. '地面の凹凸にはまった。次の2セグメントは移動を行うことができない。',
  175. '刃こぼれを起こした。使用した白兵武器の全てのダメージが戦闘終了まで-2される。',
  176. '大振りしすぎた。使用した白兵武器が搭載されている部位の反対の部位(右腕に搭載されているなら左側)に命中レベルCで命中する。',
  177. '頭を打った。パイロットの肉体的負傷が1段階上昇する。',
  178. '駆動系が損傷した。移動力が戦闘終了まで-2される(最低1)。',
  179. '間合いを取り損ねた。隣接している機体(複数の場合は1機をランダムに決定)に激突する。',
  180. '機体ごと突っ込んだ。機体が向いている方角へ移動力をすべて消費するまで移動する。',
  181. '制御系が損傷した。回避値が戦闘終了まで-1される(最低1)。',
  182. '踏み誤った。機体が向いている方角へ移動力の半分を消費するまで移動する。',
  183. 'たたらを踏んだ。機体が向いている方角へ1の移動力で移動する。',
  184. '何も起きなかった。',
  185. ]
  186. 10 dc = 2
  187. 10 then: 10 else: 0 output = table[num - dc] if table[num - dc]
  188. 10 return output
  189. end
  190. 1 def get_hit_level_table(num)
  191. table = [
  192. 84 [6, '命中レベルC'],
  193. [9, '命中レベルB'],
  194. [10, '命中レベルA'],
  195. ]
  196. 84 return get_table_by_number(num, table)
  197. end
  198. end
  199. end
  200. end

lib/bcdice/game_system/Emoklore.rb

94.92% lines covered

85.19% branches covered

59 relevant lines. 56 lines covered and 3 lines missed.
27 total branches, 23 branches covered and 4 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Emoklore < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "Emoklore"
  7. # ゲームシステム名
  8. 1 NAME = "エモクロアTRPG"
  9. # ゲームシステム名の読みがな
  10. #
  11. # 「ゲームシステム名の読みがなの設定方法」(docs/dicebot_sort_key.md)を参考にして
  12. # 設定してください
  13. 1 SORT_KEY = "えもくろあTRPG"
  14. # ダイスボットの使い方
  15. 1 HELP_MESSAGE = <<~MESSAGETEXT
  16. ・技能値判定(xDM<=y)
  17. "(個数)DM<=(判定値)"で指定します。
  18. ダイスの個数は省略可能で、省略した場合1個になります。
  19. 例)2DM<=5 DM<=8
  20. ・技能値判定(sDAa+z)
  21. "(技能レベル)DA(能力値)+(ダイスボーナス)"で指定します。
  22. ダイスボーナスの個数は省略可能で、省略した場合0になります。
  23. 技能レベルは1~3の数値、またはベース技能の場合"b"が入ります。
  24. ダイスの個数は技能レベルとダイスボーナスの個数により決定し、s+z個のダイスを振ります。(s="b"の場合はs=1)
  25. 判定値はs+aとなります。(s="b"の場合はs=0)
  26. MESSAGETEXT
  27. # ダイスボットで使用するコマンドを配列で列挙する
  28. 1 register_prefix('\d*DM<=', '(B|\d*)DA')
  29. 1 CRITICAL_VALUE = 1
  30. 1 FUMBLE_VALUE = 10
  31. # ダイスボット固有コマンドの処理を行う
  32. # @param [String] command コマンド
  33. # @return [String] ダイスボット固有コマンドの結果
  34. # @return [nil] 無効なコマンドだった場合
  35. 1 def eval_game_system_specific_command(command)
  36. 23 else: 0 case command
  37. when: 13 when /^\d*DM<=\d/
  38. 13 roll_dm(command)
  39. when: 10 when /^(B|\d*)DA\d+(\+)?\d*/
  40. 10 roll_da(command)
  41. end
  42. end
  43. 1 private
  44. # ダイスロールの共通処理
  45. # @param [Integer] num_dice
  46. # @param [Integer] success_threshold
  47. # @return [Result]
  48. 1 def dice_roll(num_dice, success_threshold)
  49. # ダイスを振った結果を配列として取得
  50. 23 values = @randomizer.roll_barabara(num_dice, 10)
  51. 23 critical = values.count(CRITICAL_VALUE)
  52. 126 success = values.count { |num| num <= success_threshold }
  53. 23 fumble = values.count(FUMBLE_VALUE)
  54. # 成功値
  55. 23 success_value = critical + success - fumble
  56. 23 result = compare_result(success_value)
  57. 23 result.text = "#{values} > #{success_value} > #{translate('Emoklore.success_count', count: success_value)} #{result.text}"
  58. 23 return result
  59. end
  60. # @param [Integer] success
  61. # @return [Result]
  62. 1 def compare_result(success)
  63. 23 then: 3 if success < 0
  64. 3 else: 20 Result.fumble(translate("fumble"))
  65. 20 then: 3 elsif success == 0
  66. 3 else: 17 Result.failure(translate("failure"))
  67. 17 then: 5 elsif success == 1
  68. 5 else: 12 Result.success(translate("success"))
  69. 12 then: 5 elsif success == 2
  70. 5 else: 7 Result.critical(translate("Emoklore.double"))
  71. 7 then: 1 elsif success == 3
  72. 1 else: 6 Result.critical(translate("Emoklore.triple"))
  73. 6 then: 4 elsif success <= 9
  74. 4 Result.critical(translate("Emoklore.miracle"))
  75. else: 2 else
  76. 2 Result.critical(translate("Emoklore.catastrophe"))
  77. end
  78. end
  79. # 技能判定
  80. # @param [String] command コマンド
  81. # @return [Result, nil] コマンドの結果
  82. 1 def roll_dm(command)
  83. 13 m = /^(\d+)?DM<=(\d+)$/.match(command)
  84. 13 else: 13 then: 0 unless m
  85. return nil
  86. end
  87. 13 then: 12 else: 1 num_dice = m[1]&.to_i || 1
  88. 13 success_threshold = m[2].to_i
  89. 13 then: 0 else: 13 if num_dice <= 0
  90. return nil
  91. end
  92. # ダイスロール本体
  93. 13 result = dice_roll(num_dice, success_threshold)
  94. 13 result.text = "(#{num_dice}DM<=#{success_threshold}) > #{result.text}"
  95. 13 return result
  96. end
  97. # 取得技能判定
  98. # @param [String] command コマンド
  99. # @return [Result, nil] コマンドの結果
  100. 1 def roll_da(command)
  101. 10 m = /^(B|\d+)?DA(\d+)(\+\d+)?$/.match(command)
  102. 10 else: 10 then: 0 unless m
  103. return nil
  104. end
  105. 10 bonus = m[3].to_i
  106. 10 then: 2 else: 8 then: 7 else: 1 num_dice = (m[1] == "B" ? 1 : (m[1]&.to_i || 1)) + bonus
  107. 10 success_threshold = m[1].to_i + m[2].to_i
  108. 10 result = dice_roll(num_dice, success_threshold)
  109. 10 result.text = "(#{command}) > (#{num_dice}DM<=#{success_threshold}) > #{result.text}"
  110. 10 return result
  111. end
  112. end
  113. end
  114. end

lib/bcdice/game_system/EndBreaker.rb

97.67% lines covered

88.89% branches covered

43 relevant lines. 42 lines covered and 1 lines missed.
9 total branches, 8 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class EndBreaker < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'EndBreaker'
  7. # ゲームシステム名
  8. 1 NAME = 'エンドブレイカー!'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'えんとふれいかあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定 (nEB)
  14. n個のD6を振る判定。ダブルトリガー発動で自動振り足し。
  15. ・各種表
  16. ・生死不明表 (LDUT)
  17. MESSAGETEXT
  18. 1 register_prefix('\d+EB', 'LDUT')
  19. 1 def initialize(command)
  20. 8 super(command)
  21. 8 @d66_sort_type = D66SortType::NO_SORT
  22. end
  23. 1 def eval_game_system_specific_command(command)
  24. 8 then: 5 else: 3 if command =~ /(\d+)EB/i
  25. 5 diceCount = Regexp.last_match(1).to_i
  26. 5 return checkRoll(diceCount)
  27. end
  28. 3 tableName = ""
  29. 3 text = ""
  30. 3 number = 0
  31. 3 case command
  32. when: 3 when "LDUT"
  33. 3 tableName = "生死不明表"
  34. 3 text, number = getLifeAndDeathUnknownResult()
  35. else: 0 else
  36. return nil
  37. end
  38. 3 result = "#{tableName}(#{number}):#{text}"
  39. 3 return result
  40. end
  41. 1 def checkRoll(diceCount)
  42. 5 debug("EndBreaker diceCount", diceCount)
  43. 5 rollCount = diceCount # ダブルトリガー
  44. 5 result = ""
  45. 5 diceFullList = []
  46. 5 body: 11 while rollCount != 0
  47. 11 diceList = @randomizer.roll_barabara(rollCount, 6).sort
  48. 11 diceFullList.concat(diceList)
  49. # 1の出目ごとにダブルトリガーで2個ダイス追加
  50. 36 rollCount = diceList.select { |i| i == 1 }.size * 2
  51. 11 result += "[#{diceList.join}]"
  52. 11 then: 6 else: 5 result += " ダブルトリガー! " if rollCount > 0
  53. end
  54. # ダイスの出目の個数を集計
  55. 5 result += " >"
  56. 5 (2..6).each do |num|
  57. 150 count = diceFullList.select { |i| i == num }.size
  58. 25 else: 11 then: 14 result += " [#{num}:#{count}個]" unless count == 0
  59. end
  60. 5 return result
  61. end
  62. 1 def getLifeAndDeathUnknownResult()
  63. 3 table = [
  64. ' 1日:生還!',
  65. ' 1日:生還!',
  66. ' 1日:生還!',
  67. ' 1日:生還!',
  68. ' 1日:生還!',
  69. ' 1日:生還!',
  70. ' 1日:生還!',
  71. ' 5日:敵に捕らわれ、ひどい暴行と拷問を受けた。',
  72. ' 2日:謎の人物に命を救われた。',
  73. '10日:奴隷として売り飛ばされた。',
  74. ' 8日:おぞましい儀式の生贄として連れ去られた。',
  75. ' 9日:幽閉・投獄された。',
  76. ' 1日:生還!',
  77. ' 7日:モンスター蠢く地下迷宮に滑落した。',
  78. '12日強力なマスカレイドにとらわれ、実験台にされた。',
  79. ' 8日:放浪中に遭遇した事件を、颯爽と解決していた。',
  80. ' 5日:飢餓状態に追い込まれた。',
  81. '15日:記憶を失い放浪した。',
  82. ' 1日:生還!',
  83. '10日:異性に命を救われて、手厚い看病を受けた。',
  84. ' 3日:負傷からくる熱病で、生死の境を彷徨った。',
  85. '11日:闘奴にされたが、戦いと友情の末に自由を獲得した。',
  86. ' 6日:負傷したまま川に落ち、遥か下流まで流された。',
  87. ' 9日:敵に連れ去られ、執拗な拷問を受け続けた。',
  88. ' 1日:生還!',
  89. ' 4日:繰り返す「死の悪夢」に苛まれた。',
  90. ' 3日:巨獣の巣に連れ去られた。',
  91. '10日:謎の集団に救われて、手厚い看病を受けた。',
  92. ' 3日:チッタニアンの集落に迷い込み、もてなしを受けた。',
  93. ' 7日:ピュアリィの群れにとらわれ、弄ばれた。',
  94. ' 1日:生還!',
  95. ' 6日:楽園のような場所を発見し、しばらく逗留した。',
  96. ' 9日:盗賊団に救われ、恩返しとして少し用心棒をした。',
  97. '10日:熱病の見せる官能的な幻影にとらわれ、彷徨った。',
  98. ' 5日:謎の賞金首に狙われ、傷めつけられていた。',
  99. ' - :「五分五分」の一般判定。失敗すると死亡。',
  100. ]
  101. 3 return get_table_by_d66(table)
  102. end
  103. end
  104. end
  105. end

lib/bcdice/game_system/EtrianOdysseySRS.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/SRS'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class EtrianOdysseySRS < SRS
  6. # ゲームシステムの識別子
  7. 1 ID = 'EtrianOdysseySRS'
  8. # ゲームシステム名
  9. 1 NAME = '世界樹の迷宮SRS'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'せかいしゆのめいきゆうSRS'
  12. # 固有のコマンドの接頭辞を設定する
  13. 1 register_prefix('2D6', 'EO', 'SQ')
  14. # 成功判定のエイリアスコマンドを設定する
  15. 1 set_aliases_for_srs_roll('EO', 'SQ')
  16. 1 HELP_MESSAGE = help_message()
  17. end
  18. end
  19. end

lib/bcdice/game_system/FateCoreSystem.rb

98.15% lines covered

96.0% branches covered

54 relevant lines. 53 lines covered and 1 lines missed.
25 total branches, 24 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class FateCoreSystem < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'FateCoreSystem'
  7. # ゲームシステム名
  8. 1 NAME = 'Fate Core System'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ふえいとこあしすてむ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ■ ファッジダイスによる判定 (xDF+y>=t)
  14. ファッジダイスをx個ダイスロールし、結果を判定します。
  15. x: ダイス数
  16. y: 修正値(省略可)
  17. t: 目標値値(省略可)
  18. 例)4DF, 4DF>=3, 4DF+1>=3
  19. MESSAGETEXT
  20. 1 register_prefix('\d+DF')
  21. 1 def eval_game_system_specific_command(command)
  22. 19 roll_df(command)
  23. end
  24. 1 private
  25. 1 def roll_df(command)
  26. 19 parser = Command::Parser.new("DF", round_type: @round_type)
  27. .enable_prefix_number()
  28. .restrict_cmp_op_to(:>=, nil)
  29. 19 parsed = parser.parse(command)
  30. 19 else: 19 then: 0 unless parsed
  31. return nil
  32. end
  33. 19 dice_list = roll_fate_dice(parsed.prefix_number)
  34. 19 total = dice_list.sum() + parsed.modify_number
  35. 19 fate_dice_list = dice_list.map do |i|
  36. 81 then: 19 if i.zero?
  37. 19 else: 62 "[ ]"
  38. 62 then: 53 elsif i.positive?
  39. 53 "[+]"
  40. else: 9 else
  41. 9 "[-]"
  42. end
  43. end
  44. 19 result = outcome(total, parsed.target_number)
  45. sequence = [
  46. 19 "(#{parsed})",
  47. "#{fate_dice_list.join()}#{Format.modifier(parsed.modify_number)}",
  48. result_ladder(total),
  49. result.text,
  50. ]
  51. 19 result.text = sequence.compact.join(" > ")
  52. 19 return result
  53. end
  54. 1 def roll_fate_dice(times)
  55. 100 @randomizer.roll_barabara(times, 3).map { |i| i - 2 }
  56. end
  57. 1 def result_ladder(total)
  58. ladder =
  59. 19 case total.clamp(-2, 8)
  60. when: 2 when 8
  61. 2 "Legendary"
  62. when: 1 when 7
  63. 1 "Epic"
  64. when: 2 when 6
  65. 2 "Fantastic"
  66. when: 2 when 5
  67. 2 "Superb"
  68. when: 2 when 4
  69. 2 "Great"
  70. when: 2 when 3
  71. 2 "Good"
  72. when: 2 when 2
  73. 2 "Fair"
  74. when: 1 when 1
  75. 1 "Average"
  76. when: 2 when 0
  77. 2 "Mediocre"
  78. when: 1 when -1
  79. 1 "Poor"
  80. else: 2 else
  81. 2 "Terrible"
  82. end
  83. 19 return "#{ladder}(#{format('%+d', total)})"
  84. end
  85. 1 def outcome(total, target)
  86. 19 then: 14 if target.nil?
  87. 14 else: 5 Result.new
  88. 5 then: 1 elsif total == target
  89. 1 else: 4 Result.success("Tie")
  90. 4 then: 1 elsif total >= target + 3
  91. 1 else: 3 Result.critical("Succeed with Style")
  92. 3 then: 2 elsif total >= target
  93. 2 Result.success("Succeed")
  94. else: 1 else
  95. 1 Result.failure("Fail")
  96. end
  97. end
  98. end
  99. end
  100. end

lib/bcdice/game_system/Fiasco.rb

98.33% lines covered

94.12% branches covered

60 relevant lines. 59 lines covered and 1 lines missed.
17 total branches, 16 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Fiasco < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Fiasco'
  7. # ゲームシステム名
  8. 1 NAME = 'フィアスコ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ふいあすこ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<INFO_MESSAGE_TEXT
  13. ・判定コマンド(FSx, WxBx)
  14. 相関図・転落要素用(FSx):相関図や転落要素のためにx個ダイスを振り、出目ごとに分類する
  15. 黒白差分判定用(WxBx) :転落、残響のために白ダイス(W指定)と黒ダイス(B指定)で差分を求める
  16. ※ WとBは片方指定(Bx, Wx)、入替指定(WxBx,BxWx)可能
  17. INFO_MESSAGE_TEXT
  18. 1 register_prefix('FS', 'W', 'B')
  19. 1 def eval_game_system_specific_command(command)
  20. 40 roll_fs(command) || roll_white_black(command) || roll_white_black_single(command)
  21. end
  22. 1 private
  23. # 6面ダイスを複数ダイスロールして、各面が出た個数をカウントする
  24. # @param command [String]
  25. # @return [String, nil]
  26. 1 def roll_fs(command)
  27. 40 m = /^FS(\d+)$/.match(command)
  28. 40 else: 4 then: 36 unless m
  29. 36 return nil
  30. end
  31. 4 dice_count = m[1].to_i
  32. 4 dice_list = @randomizer.roll_barabara(dice_count, 6)
  33. # 各出目の個数を数える
  34. 4 bucket = [nil, 0, 0, 0, 0, 0, 0]
  35. 4 dice_list.each do |val|
  36. 48 bucket[val] += 1
  37. end
  38. # "n個" 表記にする
  39. 32 bucket.map! { |count| translate("Fiasco.fs.count", count: count) }
  40. 4 return "1 => #{bucket[1]}, 2 => #{bucket[2]}, 3 => #{bucket[3]}, 4 => #{bucket[4]}, 5 => #{bucket[5]}, 6 => #{bucket[6]}"
  41. end
  42. # 白か黒かの片方だけダイスロールする
  43. #
  44. # "W4", "B6" など
  45. # @param command [String]
  46. # @return [String, nil]
  47. 1 def roll_white_black_single(command)
  48. 8 m = /^([WB])(\d+)$/.match(command)
  49. 8 else: 8 then: 0 unless m
  50. return nil
  51. end
  52. 8 a = Side.new(color(m[1]), m[2].to_i)
  53. 8 result = a.roll(@randomizer)
  54. 8 return "#{result} > #{a.color}#{a.total}"
  55. end
  56. # 白黒両方ダイスロールして、その差分を表示する
  57. # @param command [String]
  58. # @return [String, nil]
  59. 1 def roll_white_black(command)
  60. 36 m = /^([WB])(\d+)([WB])(\d+)$/.match(command)
  61. 36 else: 28 then: 8 unless m
  62. 8 return nil
  63. end
  64. 28 else: 20 case command
  65. when: 4 when /^W\d+W\d+$/
  66. 4 return "#{command}:#{translate('Fiasco.wb.duplicate_error.white')}"
  67. when: 4 when /^B\d+B\d+$/
  68. 4 return "#{command}:#{translate('Fiasco.wb.duplicate_error.black')}"
  69. end
  70. 20 a = Side.new(color(m[1]), m[2].to_i)
  71. 20 result_a = a.roll(@randomizer)
  72. 20 b = Side.new(color(m[3]), m[4].to_i)
  73. 20 result_b = b.roll(@randomizer)
  74. 20 return "#{result_a} #{result_b} > #{a.diff(b)}"
  75. end
  76. 1 def color(c)
  77. 48 then: 24 else: 24 c == "W" ? translate("Fiasco.white") : translate("Fiasco.black")
  78. end
  79. # 片方の色のダイスロールを抽象化したクラス
  80. 1 class Side
  81. 1 def initialize(color, count)
  82. 48 @color = color
  83. 48 @count = count
  84. end
  85. # @param randomizer [Randomizer]
  86. # @return [String]
  87. 1 def roll(randomizer)
  88. @dice_list =
  89. 48 then: 8 if @count == 0
  90. 8 [0]
  91. else: 40 else
  92. 40 randomizer.roll_barabara(@count, 6)
  93. end
  94. 48 @total = @dice_list.sum()
  95. 48 "#{@color}#{@total}[#{@dice_list.join(',')}]"
  96. end
  97. # もう一方の色との差分を求める
  98. # @param other [Side]
  99. # @return [String]
  100. 1 def diff(other)
  101. 20 then: 4 if @total == other.total
  102. 4 else: 16 "0"
  103. 16 then: 12 elsif @total > other.total
  104. 12 "#{@color}#{@total - other.total}"
  105. else: 4 else
  106. 4 "#{other.color}#{other.total - @total}"
  107. end
  108. end
  109. 1 attr_reader :color, :total
  110. end
  111. end
  112. end
  113. end

lib/bcdice/game_system/Fiasco_Korean.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/Fiasco"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Fiasco_Korean < Fiasco
  6. # ゲームシステムの識別子
  7. 1 ID = 'Fiasco:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '피아스코'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:피아스코'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<INFO_MESSAGE_TEXT
  14. ・판정 커맨드(FSx, WxBx)
  15. 관계, 비틀기 요소용(FSx):관계나 비틀기 요소를 위해 x개의 다이스를 굴려 나온 값별로 분류한다.
  16. 흑백차이판정용(WxBx) :비틀기, 후기를 위해 흰 다이스(W지정)과 검은 다이스(B지정)으로 차이를 구한다.
  17. ※ W와B는 한 쪽만 지정(Bx, Wx), 앞뒤 바꿔 지정(WxBx,BxWx)도 가능
  18. INFO_MESSAGE_TEXT
  19. 1 register_prefix_from_super_class()
  20. 1 def initialize(command)
  21. 20 super(command)
  22. 20 @locale = :ko_kr
  23. end
  24. end
  25. end
  26. end

lib/bcdice/game_system/FilledWith.rb

97.12% lines covered

92.73% branches covered

139 relevant lines. 135 lines covered and 4 lines missed.
55 total branches, 51 branches covered and 4 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class FilledWith < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'FilledWith'
  7. # ゲームシステム名
  8. 1 NAME = 'フィルトウィズ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ふいるとういす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定 (3FW@x#y<=z or z-3FW@x#y)
  14. 3個の6面ダイスを振る判定。
  15. @x:xにクリティカル値を入力。省略可。(省略時クリティカル値4)
  16. #y:yにファンブル値を入力。省略可(省略時ファンブル値17)
  17. <=z or z-:zに目標値を入力。±の計算に対応。省略可。
  18. ・【必殺技!】 (HST)
  19. ホムンクルス特技【必殺技!】表。
  20. ・マジカルクッキング (COOKx)
  21. マジカルクッキングのシェフのおすすめコース。
  22. xにクッキングレベルを入力。(1-8)
  23. ・ナンバーワンくじ (LOTN or LOTP)
  24. LOTNでノーマルくじ、LOTPでプレミアムくじ。(GURPS-FW版)
  25. ----------夢幻の迷宮用----------
  26. ・共通書式
  27. a:aに地形(1-6の数字)を入力。省略可。(省略時ランダム決定)
  28. (1:洞窟 2:遺跡 3:山岳 4:水辺 5:森林 6:墓場)
  29. d:dに難易度を入力。(E:初級 N:中級 H:上級 L:悪夢 X:伝説)
  30. ・ランダムイベント表 (RANDda)
  31. ・ランダムエンカウント表 (RENCda)
  32. ・エネミーデータ表 (REDde)
  33. エネミーデータ参照表。
  34. GMがシークレットダイスで参照するとPLに知られずにエネミーデータを参照可能。
  35. e:3桁のイベントダイスを入力(D666の結果)。
  36. ・トラップ表 (TRAPd)
  37. ・財宝表 (TRSr±x)
  38. r:rに財宝ランクを入力。
  39. ±x:xに財宝ランク修正値を入力。省略可。
  40. ・迷宮追加オプション表(ROPd)
  41. MESSAGETEXT
  42. 1 register_prefix('3FW', '[\+\-\d]*-3FW', 'LOT[NP]', 'HST', 'COOK[1-8]', 'RAND', 'RENC', 'RED', 'TRS', 'TRAP[ENHLX]', 'ROP[ENHLX]')
  43. 1 def initialize(command)
  44. 47 super(command)
  45. 47 @d66_sort_type = D66SortType::NO_SORT; # d66の差し替え
  46. end
  47. # @param command [String] コマンド
  48. # @return [Result, nil] 固有コマンドの評価結果
  49. 1 def eval_game_system_specific_command(command)
  50. # ダイスロールコマンド
  51. 47 result = FW.roll(command, @randomizer)
  52. 47 then: 10 else: 37 return result if result
  53. # 各種コマンド
  54. 37 case command
  55. when: 4 when "LOTN"
  56. 4 roll_jump_table("ナンバーワンノーマルくじ", LOT_NORMAL_TABLES[1])
  57. when: 3 when "LOTP"
  58. 3 roll_jump_table("ナンバーワンプレミアムくじ", LOT_PREMIUM_TABLES[1])
  59. when: 3 when /COOK([1-8])/
  60. 3 lv = Regexp.last_match(1).to_i
  61. 3 roll_jump_table("マジカルクッキング", COOK_TABLES[lv])
  62. when: 3 when /TRAP[ENHLX]/
  63. 3 roll_trap_table(command)
  64. when: 6 when /TRS.*/i
  65. 6 getTresureResult(command)
  66. when: 5 when /RAND.*/
  67. 5 roll_random_event_table(command)
  68. when: 2 when /RENC.*/
  69. 2 roll_random_event_table(command)
  70. when: 6 when /RED.*/i
  71. 6 fetch_enemy_data(command)
  72. when: 4 when /ROP[ENHLX]/
  73. 4 roll_random_option_table(command)
  74. else: 1 else
  75. 1 roll_tables(command, TABLES)
  76. end
  77. end
  78. # 表を振った結果を独自の書式で整形する
  79. # @param table_name [String] 表の名前
  80. # @param number [String] 出目の文字列
  81. # @param result [String] 結果の文章
  82. # @return [String]
  83. 1 def format_table_roll_result(table_name, number, result)
  84. 10 "#{table_name}(#{number}):#{result}"
  85. end
  86. # ジャンプする項目を含む表を振る
  87. # @param table_name [String] 表の名前
  88. # @param table [DiceTable::RangeTable] 振る対象の表
  89. # @return [Result]
  90. 1 def roll_jump_table(table_name, table)
  91. # 出目の配列
  92. 10 values = []
  93. 10 loop do
  94. 38 roll_result = table.roll(@randomizer)
  95. 38 values.concat(roll_result.values)
  96. 38 content = roll_result.content
  97. 38 case content
  98. when: 10 when String
  99. 10 return Result.new(format_table_roll_result(table_name, values.join, content))
  100. when Proc
  101. when: 28 # 次の繰り返しで指定された表を参照する
  102. 28 table = content.call
  103. else: 0 else
  104. raise TypeError
  105. end
  106. end
  107. end
  108. 1 class FW
  109. 1 attr_accessor :dice_count, :target, :critical, :fumble
  110. 1 def initialize
  111. 10 @target = nil
  112. end
  113. 1 def self.roll(command, randomizer)
  114. 47 fw = parse(command)
  115. 47 then: 10 else: 37 return fw&.roll(randomizer)
  116. end
  117. 1 def self.parse(command)
  118. 47 then: 3 if (m = /^(\d[+\-\d]*)-(\d+)FW(?:@(\d+))?(?:\#(\d+))?$/.match(command))
  119. 3 new.tap do |fw|
  120. 3 fw.dice_count = m[2].to_i
  121. 3 fw.target = Arithmetic.eval(m[1], RoundType::FLOOR)
  122. 3 then: 1 else: 2 fw.critical = m[3]&.to_i || 4
  123. 3 then: 1 else: 2 fw.fumble = m[4]&.to_i || 17
  124. else: 44 end
  125. 44 then: 7 else: 37 elsif (m = /(\d+)FW(?:@(\d+))?(?:\#(\d+))?(?:<=([+\-\d]+))?/.match(command))
  126. 7 new.tap do |fw|
  127. 7 fw.dice_count = m[1].to_i
  128. 7 then: 3 else: 4 fw.target = Arithmetic.eval(m[4], RoundType::FLOOR) if m[4]
  129. 7 then: 1 else: 6 fw.critical = m[2]&.to_i || 4
  130. 7 then: 1 else: 6 fw.fumble = m[3]&.to_i || 17
  131. end
  132. end
  133. end
  134. 1 def roll(randomizer)
  135. 10 dice_list = randomizer.roll_barabara(@dice_count, 6)
  136. 10 dice = dice_list.sum()
  137. 10 dice_str = dice_list.join(",")
  138. 10 res = result(dice)
  139. sequence = [
  140. 10 "(#{expr})",
  141. "#{dice}[#{dice_str}]",
  142. res.text,
  143. ].compact
  144. 10 res.text = sequence.join(" > ")
  145. 10 return res
  146. end
  147. 1 private
  148. 1 def expr
  149. 10 ret = "#{@dice_count}FW"
  150. 10 then: 2 else: 8 ret += "@#{@critical}" if @critical != 4
  151. 10 then: 2 else: 8 ret += "##{@fumble}" if @fumble != 17
  152. 10 then: 6 else: 4 ret += "<=#{@target}" if @target
  153. 10 return ret
  154. end
  155. 1 def result(total)
  156. 10 then: 3 if total <= @critical
  157. 3 else: 7 Result.critical("クリティカル!")
  158. 7 then: 2 elsif total >= @fumble
  159. 2 else: 5 Result.fumble("ファンブル!")
  160. 5 then: 4 elsif @target
  161. 4 success = @target - total
  162. 4 then: 3 if total <= @target
  163. 3 Result.success("成功(成功度:#{success})")
  164. else: 1 else
  165. 1 Result.failure("失敗(失敗度:#{success})")
  166. end
  167. else: 1 else
  168. 1 Result.new
  169. end
  170. end
  171. end
  172. TABLES = {
  173. 1 "HST" => DiceTable::Table.new(
  174. "【必殺技!】",
  175. "1D6",
  176. [
  177. '〔命中〕判定に出目[1,1,1]でクリティカル。更に致傷力に「SLv×20」のボーナスを得る。',
  178. '〔命中〕判定と致傷力に「SLv×10」のボーナスを得る。',
  179. '致傷力に「SLv×10」のボーナスを得る。',
  180. '攻撃が命中するとバッドステータス「転倒」を与える。',
  181. '通常攻撃。',
  182. '〔命中〕判定に[6,6,6]でファンブル。更に、使用者がバッドステータス「転倒」を受ける。',
  183. ]
  184. )
  185. }.freeze
  186. 1 class Row
  187. 1 def initialize(body, *args)
  188. 268 @body = body
  189. 268 @args = args
  190. end
  191. 1 def format(difficulty)
  192. 27 args = @args.map { |e| e[difficulty.index] }
  193. 14 Kernel.format(@body, *args)
  194. end
  195. end
  196. 1 class Difficulty
  197. 1 DIFFICULTYS = ["E", "N", "H", "L", "X"].freeze
  198. 1 NAMES = {
  199. "E" => "初級",
  200. "N" => "中級",
  201. "H" => "上級",
  202. "L" => "悪夢",
  203. "X" => "伝説",
  204. }.freeze
  205. 1 def initialize(sign)
  206. 20 @sign = sign
  207. end
  208. 1 def index
  209. 19 @index ||= DIFFICULTYS.find_index(@sign)
  210. end
  211. 1 def name
  212. 20 @name ||= NAMES[@sign]
  213. end
  214. end
  215. TRAP_TABLE = [
  216. 1 Row.new("トライディザスター:宝箱から広範囲に火炎・冷気・電撃が放たれる罠。PC全員に「%s」の「火炎」「冷気」「電撃」属性ダメージ。", ['3D6+3', '3D6+50', '3D6+70', '3D6+100', '300']),
  217. Row.new("ペトロブラスター:広範囲に石化光線を放つ罠。PC全員[抵抗-%s]判定を行い、失敗したPCはBS「石化」を受ける。", [2, 4, 6, 8, 10]),
  218. Row.new("クロスボウストリーム:宝箱から矢の嵐が放たれる罠。PC全員に「%s」の「刺突」属性ダメージ。「ドッジ-%s」で〔回避〕が可能。", ['3D6+20', '3D6+40', '3D6+60', '3D6+90', '200'], [4, 6, 8, 10, 20]),
  219. Row.new("フォーチュンイーター:PC全員の幸運を食らい、Ftを%s点減少させる。Ftが0の場合「%s」点の防護点無視ダメージ。", [1, 2, 3, 4, 5], ['3D6+30', '3D6+50', '3D6+70', '3D6+100', '300']),
  220. Row.new("スロット:解除に失敗しても害はないが、スロットが揃うまで開かない宝箱。スロットを1回まわすには%sGPが必要。行動を消費して[感覚-%s]判定に成功すればスロットは揃う。有利な特異点「ビビット反射」があれば判定に+4のボーナス。", [100, 300, 600, 1000, 10000], [4, 6, 8, 10, 15]),
  221. Row.new("テレポーター:PC全員(とエンカウントしているエネミー)を転送して道に迷わせる。「財宝ランク」が1段階減少する。"),
  222. Row.new("アイスコフィン:宝箱を開けようとしたキャラクターを氷漬けにする罠。対象1体に「%s」の「冷気」属性ダメージ。更にFPにも%s点の防護点無視ダメージ。", ['3D6+30', '3D6+50', '3D6+70', '3D6+100', '300'], [5, 10, 15, 20, 30]),
  223. Row.new("クロスボウ:宝箱を開けようとしたキャラクターに強力な矢が放たれる罠。対象1体に「%s」の「刺突」属性ダメージ。「ドッジ-%s」", ['3D6+20', '3D6+40', '3D6+60', '3D6+90', '200'], [4, 6, 8, 10, 20]),
  224. Row.new("毒針:宝箱を開けようとしたキャラクターに毒針を突き刺す罠対象1体に%s点の防護点無視ダメージ。更に[抵抗-%s]判定に失敗するとシナリオ終了まであらゆる判定に-2のペナルティ。", [15, 30, 45, 60, 150], [4, 6, 8, 10, 15]),
  225. Row.new("アラーム:即座にその地形のエンカウント表を振って、それに対応したエネミーが出現する。出現したエネミーはそのターンから行動順に組み込まれる。出現するエネミー以外の記述は無視する。"),
  226. Row.new("殺人鬼の斧:宝箱を開けようとしたキャラクターに斧が振り下ろされる罠。対象1体に「%s」の「打撃」「斬撃」属性ダメージ。「ドッジ-%s」か「シールド-%s」で〔回避〕が可能。", ['3D6+30', '3D6+50', '3D6+70', '3D6+100', '300'], [4, 6, 8, 10, 20], [4, 6, 8, 10, -20]),
  227. Row.new("死神:宝箱を開けようとしたキャラクターに死神を取り憑かせる罠。4ラウンド目が終了するまであらゆる判定に-3のペナルティを受け、4ラウンド目の終了と同時に「%s」の防護点無視ダメージ。", ['3D6+30', '3D6+50', '3D6+70', '3D6+100', '300']),
  228. Row.new("幻の宝:宝箱に偽の財宝を入れ、本物の財宝を入手させない罠。トラップが発動すると価値の無い偽の宝物「幻の宝」を入手してしまう。「幻の宝」はアイテム欄を3つ占有し、シナリオ終了まで捨てられない。アイテム欄に空きがない場合は、何かを捨てて誰かが必ず持たなくてはならない。"),
  229. Row.new("エクスプロージョン:宝箱が大爆発を起こし、中身を粉々にしてしまう罠。宝箱の中身は消滅する。PC全員に「%s」の「打撃」「火炎」属性ダメージ。", ['3D6+10', '3D6+30', '3D6+50', '3D6+80', '200']),
  230. Row.new("レインボーポイズン:宝箱から七色の毒ガスが放たれる罠。PC全員に「%s」の防護点無視ダメージ。更にシナリオ終了まであらゆる判定に-2のペナルティ。[抵抗-%s]判定に成功すれば無効。", ['3D6+10', '3D6+30', '3D6+50', '3D6+80', '200'], [4, 6, 8, 10, 15]),
  231. Row.new("デスクラウド:宝箱から致死性の毒ガスを放つ罠。PC全員を即死させる。[抵抗-%s]判定に成功すれば無効。", [2, 4, 6, 8, 12]),
  232. ].freeze
  233. # 夢幻の迷宮トラップ表
  234. 1 def roll_trap_table(command)
  235. 3 m = /^TRAP([ENHLX])$/.match(command)
  236. 3 else: 3 then: 0 unless m
  237. return nil
  238. end
  239. 3 difficality = Difficulty.new(m[1])
  240. 3 number = @randomizer.roll_sum(3, 6)
  241. 3 chosen = TRAP_TABLE[number - 3]
  242. 3 return "トラップ表<#{difficality.name}>(#{number}):#{chosen.format(difficality)}"
  243. end
  244. 1 class D66Table
  245. 1 def initialize(name, rows)
  246. 1 @name = name
  247. 1 @rows = rows
  248. end
  249. 1 def roll(randomizer, difficality)
  250. 4 value = randomizer.roll_d66(D66SortType::NO_SORT)
  251. 4 chosen = @rows[value]
  252. 4 "#{@name}<#{difficality.name}>(#{value}):#{chosen.format(difficality)}"
  253. end
  254. end
  255. 1 OPTION_TABLE = D66Table.new(
  256. "迷宮追加オプション表",
  257. {
  258. 11 => Row.new("黄金の迷宮(財宝ランク+2):全てが黄金で彩られた迷宮。財宝ランクが大きく上昇する。"),
  259. 12 => Row.new("密林の迷宮(財宝ランク+1):密林の中にひっそりとたたずむ迷宮。分類が「魔獣」「獣人」「霊獣」のエネミーが行うあらゆる判定に+2のボーナス。"),
  260. 13 => Row.new("カラクリの迷宮:複雑なカラクリが周囲で絶え間なく動いている迷宮。分類「ギア」のエネミーが行うあらゆる判定に+2のボーナス。クリア時に「アタッチメント割引券」を全員が%s枚獲得。", [1, 2, 3, 5, 10]),
  261. 14 => Row.new("フラウの舞踏会:あちこちに花畑のある迷宮。フラウが発生するランダムイベントが発生した際、「この迷宮を制覇して、私達が舞踏会を開けるようにしてね」とお願いされ、クリア時の報酬に%sが追加される。", ['「キノコの帽子」(装飾品)', '「猛毒の花」(装飾品)', '「フルブロウン」(鎧)', '「緊急召喚の宝珠」(装飾品)', '魔将樹の大剣(剣)']),
  262. 15 => Row.new("アズマ風の迷宮:風流なアズマ風の迷宮。武器に「刀」を持つエネミーが行うあらゆる判定に+2のボーナス。クリア時に「アタッチメント割引券」を全員が%s枚獲得。", [1, 2, 3, 5, 10]),
  263. 16 => Row.new("枯れた泉の迷宮:「全地形1-1」の回復の泉が全て枯れており、回復効果を得ることができない。「山岳1-6」の貴重な水源や、「水辺1-6」の毒の泉などはそのまま存在する。"),
  264. 21 => Row.new("天空への道(財宝ランク+1):上へ上へと果てしなく登っていく迷宮。空気が薄くなって疲労しやすくなる。【特技】特技などによるFP消費が全て+3。"),
  265. 22 => Row.new("灼熱焦土の迷宮(財宝ランク+1):とてつもなく暑く、あちこちで炎が燃え盛る迷宮。エネミーが行う「火炎」属性を含む攻撃の致傷力に+%sのボーナス。", [10, 20, 30, 50, 100]),
  266. 23 => Row.new("灼熱焦土の迷宮(財宝ランク+1):とてつもなく寒く、気温が氷点下の迷宮。エネミーが行う「冷気」属性を含む攻撃の致傷力に+%sのボーナス。", [10, 20, 30, 50, 100]),
  267. 24 => Row.new("盗賊王の迷宮:迷宮内での罠や鍵を解除する[感覚]判定に-3のペナルティ。4ラウンドまでに出現した宝箱の「財宝ランク」+1。"),
  268. 25 => Row.new("ミミック狂暴化:「全地形2-5」のミミックの致傷力に+%sのボーナス。ミミックを見破った場合に得られるGPが%sGP増加する。", [20, 30, 50, 80, 150], [500, 1000, 3000, 5000, 20000]),
  269. 26 => Row.new("トレジャーイーター狂暴化:「全地形2-6」のトレジャーイーターを見破る[知力]判定に-3のペナルティ。4ラウンドまでに出現した宝箱の「財宝ランク」+1。"),
  270. 31 => Row.new("暗闇の迷宮:どこもかしこも真っ暗な迷宮。「猫の目」などがなければ視覚に関する[感覚]判定に-5のペナルティ。"),
  271. 32 => Row.new("騒音の迷宮:常に大音量で謎の音楽(BGM)が鳴っている迷宮。聴覚に関する[感覚]判定に-5のペナルティ。"),
  272. 33 => Row.new("未知の怪物の迷宮(財宝ランク+1):エネミーの姿がシルエットのみになる迷宮。エネミーのデータがいかなる手段でも判明させられなくなる。(通常通り〔HP〕〔FP〕〔先制〕は判明する)"),
  273. 34 => Row.new("氾濫中の迷宮:大雨が降っており、川などが氾濫している迷宮。水泳を行う際の[敏捷]判定に-5のペナルティ。「森林3-6」の山火事イベントの効果は無視できる。"),
  274. 35 => Row.new("間抜けの迷宮(財宝ランク+1):頭がおかしくなりそうな極彩色の迷宮。[知力][意志]判定に-2のペナルティ。[知力]や[意志]そのものが下がるわけではない。"),
  275. 36 => Row.new("瘴気の迷宮(財宝ランク+1):生命力を奪う紫の霧で満ちた迷宮。〔HP〕の最大値に-%sのペナルティ。", [10, 20, 30, 40, 50]),
  276. 41 => Row.new("加速する迷宮:狂ったように針の動く時計が多数された迷宮。「CT:安息の日」以外の【特技】が「CT:なし」になる。"),
  277. 42 => Row.new("停滞する迷宮(財宝ランク+1):動かない時計が多数設置された迷宮。「CT:安息の日」以外のCTの存在する【特技】が「CT:シナリオ終了」になる。この効果はシナリオ終了まで持続する。"),
  278. 43 => Row.new("猛毒の迷宮(財宝ランク+1):見るからに毒々しい紫色の沼があちこちにある迷宮。エネミーが行う、名称に「毒」もしくは「ポイズン」が入る【特技】や、名称に「毒」もしくは「ポイズン」が入るトラップの致傷力に+%sのボーナス。", [10, 20, 40, 50, 100]),
  279. 44 => Row.new("死の迷宮(財宝ランク+2):死の運命から逃れることのできない、血まみれの迷宮。「生命保険証」の効果が適用されない。"),
  280. 45 => Row.new("幸運の迷宮:何者かの加護を感じる迷宮。PC全員のFtの最大値と現在値に+1のボーナス。この効果はシナリオ終了まで持続する。"),
  281. 46 => Row.new("不運の迷宮:PC全員のFt最大値と現在値に-1のペナルティ。この効果はシナリオ終了まで持続する。"),
  282. 51 => Row.new("レアメタルの迷宮:非常にレアなエネミー「レアメタルキャンディー」「レアメタルクラウン」が生息している迷宮。キャンディークラウン(CL40)、ゴールデンクラウン(CL177)から獲得できる通常ドロップのGPが5倍になる。"),
  283. 52 => Row.new("魔力の泉:PCとエネミーの双方が、〔FP〕を消費せずに【魔法】を使用できるようになる。最終的な消費〔FP〕が最大〔FP〕より大きい【魔法】は使用できない。"),
  284. 53 => Row.new("ブルーの迷宮:陰鬱な気分になり、他のキャラクターと関わる気力を失う。PC全員が不利な特異点「嫌な奴」を1段階得る。"),
  285. 54 => Row.new("レッドの迷宮:なぜか興奮して非常に好戦的になる。PC全員が不利な特異点「脳みそ筋肉」を得る。交戦中に「1:回復系」のイベントが発生しても戦闘を終了させることができない。"),
  286. 55 => Row.new("ピンクの迷宮:なんだか身近な異性(同性も?)が気になって仕方なくなる。PC全員が不利な特異点「英雄色を好む」を得る。魔族も戦闘意欲を失い、「分類:魔族」のエネミーが出現するイベントは無視する。"),
  287. 56 => Row.new("ハズレの迷宮(財宝ランク-1):ツギハギだらけの壁などでできた、ハリボテのような貧相な迷宮。宝箱の中身もなんだか貧相になる。"),
  288. 61 => Row.new("ラダマンティスの迷宮(財宝ランク+2):第一魔将ラダマンティスの像が入口に設置された迷宮。全てのエネミーが行うあらゆる判定に+2のボーナス。また、「遺跡6-6」のイベントのダメージ+%s。", [20, 40, 60, 80, 150]),
  289. 62 => Row.new("グレイヴディガーの迷宮(財宝ランク+2):第二魔将グレイヴディガーの像が入口に設置された迷宮。「分類:アンデッド」のエネミーが行うあらゆる判定に+5のボーナス。"),
  290. 63 => Row.new("ハイペリオンの迷宮(財宝ランク+2):第三魔将ハイペリオンの像が入口に設置された迷宮。全てのエネミーが「ターン開始」時に〔HP〕を全回復する。"),
  291. 64 => Row.new("ムスペルニヴルの迷宮(財宝ランク+2):勇ましくも美しい女性の像が設置された迷宮。エネミーが行う「火炎」もしくは「冷気」属性を含む攻撃の致傷力に+%sのボーナス。", [20, 40, 60, 80, 150]),
  292. 65 => Row.new("ウェルスの迷宮:人懐っこそうなアズマ風の青年が設置された迷宮。シナリオ上で第五魔将の正体が明らかに鳴っている場合のみ、PC全員のFtの最大値と現在値に+5のボーナス。この効果はシナリオ終了まで持続する。"),
  293. 66 => Row.new("バロールの迷宮(財宝ランク+2):第六魔将バロールの像が入口に設置された迷宮。「分類:ギア」のエネミーが行うあらゆる判定に+5のボーナス。"),
  294. }
  295. )
  296. # 夢幻の迷宮追加オプション表
  297. 1 def roll_random_option_table(command)
  298. 4 m = /^ROP([ENHLX])$/.match(command)
  299. 4 else: 4 then: 0 unless m
  300. return nil
  301. end
  302. 4 difficality = Difficulty.new(m[1])
  303. 4 return OPTION_TABLE.roll(@randomizer, difficality)
  304. end
  305. # 夢幻の迷宮ランダムイベント表
  306. 1 def roll_random_event_table(command)
  307. 7 m = /^(RAND|RENC)([ENHLX])([1-6])?$/.match(command)
  308. 7 else: 7 then: 0 unless m
  309. return nil
  310. end
  311. 7 then: 5 else: 2 type = m[1] == "RAND" ? nil : 4
  312. 7 difficulty = Difficulty.new(m[2])
  313. 7 then: 2 else: 5 area = m[3]&.to_i || @randomizer.roll_once(6)
  314. 7 table = EVENT_TABLES[area - 1]
  315. 7 return table.roll(@randomizer, difficulty, type: type)
  316. end
  317. end
  318. end
  319. end
  320. 1 require "bcdice/game_system/filled_with/lot_tables"
  321. 1 require "bcdice/game_system/filled_with/enemy_data_tables"
  322. 1 require "bcdice/game_system/filled_with/event_tables"
  323. 1 require "bcdice/game_system/filled_with/cook_tables"
  324. 1 require "bcdice/game_system/filled_with/tresure_tables"

lib/bcdice/game_system/FinalFantasyXIV.rb

100.0% lines covered

94.44% branches covered

49 relevant lines. 49 lines covered and 0 lines missed.
18 total branches, 17 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class FinalFantasyXIV < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "FinalFantasyXIV"
  7. # ゲームシステム名
  8. 1 NAME = "FINAL FANTSY XIV TTRPG"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "ふあいなるふあんたしい14TTRPG"
  11. 1 HELP_MESSAGE = <<~TEXT
  12. ・アビリティ判定 nAB+m>=x
  13. d20のアビリティ判定を行う。ダイス数が指定された場合、大きい出目1個を採用する。
  14. n: ダイス数(省略時 1)
  15. m: 修正値(省略可)
  16. x: 目標値(省略可)
  17. 基本効果のみ、ダイレクトヒット、クリティカルを自動判定。
  18. 例)AB, AB+5, AB+5>=14, 2AB+5>=14
  19. ・行為判定 nDC+m>=x
  20. アビリティ判定と同様。
  21. 失敗、成功を自動判定。
  22. TEXT
  23. 1 register_prefix('\d*AB', '\d*DC')
  24. 1 def eval_game_system_specific_command(command)
  25. 40 return abirity_roll(command) || action_roll(command)
  26. end
  27. 1 private
  28. 1 def abirity_roll(command)
  29. 40 parser = Command::Parser.new("AB", round_type: round_type)
  30. .enable_prefix_number()
  31. .restrict_cmp_op_to(:>=, nil)
  32. 40 cmd = parser.parse(command)
  33. 40 else: 20 then: 20 return nil unless cmd
  34. 20 times = cmd.prefix_number || 1
  35. 20 dice_list_full = @randomizer.roll_barabara(times, 20).sort
  36. 20 then: 8 else: 12 dice_list_full_str = "[#{dice_list_full.join(',')}]" if times > 1
  37. 20 dice_list = dice_list_full[-1, 1]
  38. 20 dice_result = dice_list[0]
  39. 20 total = dice_result + cmd.modify_number
  40. result =
  41. 20 then: 4 if dice_result == 20
  42. 4 else: 16 Result.critical(translate("critical"))
  43. 16 then: 8 elsif cmd.cmp_op.nil?
  44. 8 else: 8 Result.new
  45. 8 then: 4 elsif total >= cmd.target_number
  46. 4 Result.success(translate("FinalFantasyXIV.directhit"))
  47. else: 4 else
  48. 4 Result.failure(translate("FinalFantasyXIV.normalhit"))
  49. end
  50. sequence = [
  51. 20 "(#{cmd.to_s(:after_modify_number)})",
  52. dice_list_full_str,
  53. "#{dice_result}[#{dice_list.join(',')}]#{Format.modifier(cmd.modify_number)}",
  54. total,
  55. result.text
  56. ].compact
  57. 20 result.text = sequence.join(" > ")
  58. 20 result
  59. end
  60. 1 def action_roll(command)
  61. 20 parser = Command::Parser.new("DC", round_type: round_type)
  62. .enable_prefix_number()
  63. .restrict_cmp_op_to(:>=, nil)
  64. 20 cmd = parser.parse(command)
  65. 20 else: 20 then: 0 return nil unless cmd
  66. 20 times = cmd.prefix_number || 1
  67. 20 dice_list_full = @randomizer.roll_barabara(times, 20).sort
  68. 20 then: 6 else: 14 dice_list_full_str = "[#{dice_list_full.join(',')}]" if times > 1
  69. 20 dice_list = dice_list_full[-1, 1]
  70. 20 dice_result = dice_list[0]
  71. 20 total = dice_result + cmd.modify_number
  72. result =
  73. 20 then: 10 if cmd.cmp_op.nil?
  74. 10 else: 10 Result.new
  75. 10 then: 4 elsif total >= cmd.target_number
  76. 4 Result.success(translate("success"))
  77. else: 6 else
  78. 6 Result.failure(translate("failure"))
  79. end
  80. sequence = [
  81. 20 "(#{cmd.to_s(:after_modify_number)})",
  82. dice_list_full_str,
  83. "#{dice_result}[#{dice_list.join(',')}]#{Format.modifier(cmd.modify_number)}",
  84. total,
  85. result.text
  86. ].compact
  87. 20 result.text = sequence.join(" > ")
  88. 20 result
  89. end
  90. end
  91. end
  92. end

lib/bcdice/game_system/FinalFantasyXIV_English.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/FinalFantasyXIV"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class FinalFantasyXIV_English < FinalFantasyXIV
  6. # ゲームシステムの識別子
  7. 1 ID = "FinalFantasyXIV:English"
  8. # ゲームシステム名
  9. 1 NAME = "FINAL FANTSY XIV TTRPG(English)"
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = "国際化:English:FINAL FANTASY XIV TTRPG"
  12. 1 HELP_MESSAGE = <<~TEXT
  13. Ability Checks nAB+m>=CR
  14. Perform a d20 ability check. If a die count is specified, the highest roll is adopted.
  15. n: die count(optional)
  16. m: modifiy number(optional)
  17. CR: Challenge Ratting(optional)
  18. Base Effect only, Direct hit and Critical are automatically evaluated.
  19. Example: AB, AB+5, AB+5>=14, 2AB+5>=14
  20. Making checks nDC+m>=CR
  21. Same as ability check.
  22. Success and Failure ar automatically evaluated.
  23. TEXT
  24. 1 register_prefix_from_super_class()
  25. 1 def initialize(command)
  26. 20 super(command)
  27. 20 @locale = :en_us
  28. end
  29. end
  30. end
  31. end

lib/bcdice/game_system/FullFace.rb

100.0% lines covered

100.0% branches covered

68 relevant lines. 68 lines covered and 0 lines missed.
21 total branches, 21 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class FullFace < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'FullFace'
  7. # ゲームシステム名
  8. 1 NAME = 'フルフェイス'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ふるふえいす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGETEXT
  13. ■判定 x+bFF<=a[,t][&d] x:ヒート(省略時は3) b:判定修正 a:能力値 t:難易度(省略可) d:基本ダメージ(省略可)
  14. 例)FF<=2: 能力値2で判定し、その結果(成功数,1の目の数,6の目の数,バースト)を表示。
  15. 6FF<=3: ヒート6,能力値3で戦闘判定し、その結果( 〃 )を表示。
  16. 8+2FF<=3: ヒート8,判定修正+2,能力値3で戦闘判定し、その結果( 〃 )を表示。
  17. FF<=2,1: 能力値2,難易度1で判定し、その結果(成功数,1の目の数,6の目の数,成功・失敗,バースト)を表示。
  18. 6FF<=3,2&1:ヒート6,能力値3,難易度2,基本ダメージ1で戦闘判定し、その結果(成功数,1の目の数,6の目の数,ダメージ,バースト)を表示。
  19. ■ジャンク表 JKT
  20. INFO_MESSAGETEXT
  21. 1 def initialize(command)
  22. 14 super(command)
  23. 14 @sort_barabara_dice = true # バラバラロール(Bコマンド)でソート有
  24. end
  25. 1 def eval_game_system_specific_command(command)
  26. 14 resolute_action(command) ||
  27. roll_tables(command, TABLES)
  28. end
  29. 1 private
  30. # 戦闘判定
  31. # @param [String] command
  32. # @return [Result]
  33. 1 def resolute_action(command)
  34. 14 m = /^(\d*)([+\d]+)*FF<=(\d)(,(\d))?(&(\d))?$/.match(command)
  35. 14 else: 12 then: 2 return nil unless m
  36. 12 heat_level = m[1].to_i
  37. 12 then: 4 else: 8 heat_level = 3 if heat_level == 0
  38. 12 modify = Arithmetic.eval("0#{m[2]}", @round_type)
  39. 12 status_no = m[3].to_i
  40. 12 target_no = m[5].to_i
  41. 12 damage_no = m[7].to_i
  42. 12 dice_array = []
  43. 12 dice = @randomizer.roll_barabara(heat_level, 6).sort
  44. 12 ones = dice.count(1)
  45. 12 sixs = dice.count(6)
  46. 88 success_num = dice.count { |val| val <= status_no }
  47. 12 dice_array.push(dice.join(","))
  48. 12 then: 1 else: 11 if modify > 0
  49. 1 dice = @randomizer.roll_barabara(modify, 6).sort
  50. 1 ones += dice.count(1)
  51. 3 success_num += dice.count { |val| val <= status_no }
  52. 1 dice_array.push(dice.join(","))
  53. end
  54. 12 ones_total = ones
  55. 12 body: 9 while ones > 0
  56. 9 dice = @randomizer.roll_barabara(ones, 6).sort
  57. 9 ones = dice.count(1)
  58. 9 ones_total += ones
  59. 18 success_num += dice.count { |val| val <= status_no }
  60. 9 dice_array.push(dice.join(","))
  61. end
  62. 12 return Result.new.tap do |result|
  63. 12 command_out = "(#{heat_level}#{Format.modifier(modify)}FF<=#{status_no}"
  64. 12 then: 1 if sixs >= 2
  65. 1 result.fumble = true
  66. 1 result.condition = false
  67. else: 11 else
  68. 11 result.condition = (success_num > 0)
  69. 11 result.critical = (ones_total > 0)
  70. end
  71. 12 result_txt = []
  72. 12 result_txt.push("成功度(#{success_num})")
  73. 12 then: 6 else: 6 result_txt.push("1の目(#{ones_total})") if ones_total > 0
  74. 12 then: 9 else: 3 result_txt.push("6の目(#{sixs})") if sixs > 0
  75. 12 then: 3 else: 9 if target_no > 0
  76. 3 command_out += ",#{target_no}"
  77. 3 then: 2 if success_num >= target_no
  78. 2 result_txt.push("成功")
  79. 2 result.condition = true
  80. else: 1 else
  81. 1 result_txt.push("失敗")
  82. 1 result.condition = false
  83. end
  84. end
  85. 12 then: 2 else: 10 if damage_no > 0
  86. 2 command_out += "&#{damage_no}"
  87. 2 damage = damage_no + ones_total
  88. 2 result_txt.push("ダメージ(#{damage})")
  89. end
  90. 12 then: 1 else: 11 result_txt.push("バースト") if result.fumble?
  91. 12 command_out += ")"
  92. sequence = [
  93. 12 command_out,
  94. dice_array.join('+').to_s,
  95. result_txt.join(',').to_s,
  96. ].compact
  97. 12 result.text = sequence.join(" > ")
  98. end
  99. end
  100. TABLES = {
  101. 1 "JKT" => DiceTable::Table.new(
  102. "ジャンク表",
  103. "2D6",
  104. [
  105. "命欲しさに重要な情報を吐いた。セッションのボスに関する情報を得る。",
  106. "ユニットの機密文書だ。この戦闘で獲得したユニットがあるなら、そのうち好きなユニット1つを経験点を消費せずに常備化できる。",
  107. "違法アップロードされた個人情報のデータだ。このセッション中、エネミーと出会ったとき、詳細なデータが即座に公開される(GMはできるだけ拒否しないこと)。",
  108. "鍵を持っていた。近くに施錠された扉や箱などがあるなら、そのうちの1つを開けることができる。",
  109. "何も見つけられなかったが、敵を倒したことによって自信を得た。このセッション中のみ、1回だけ自身の判定で出た6の目を1つ消すことができる。",
  110. "自爆装置だ。何も残らなかった。",
  111. "使い捨ての武器を手に入れた。このセッション中のみ、1回だけ「近接攻撃5『本能』」の攻撃アクションを行える。",
  112. "敵が改心した。倒されたキャラクターがまだ生きているなら、そのうちの一人が君たちに協力を申し込んでくる(このセッション限定の恩恵「人脈:協力者」を得る)。",
  113. "金を手に入れた。キャラクター全員、アフターフェイズに配布される経験点が1増加する。",
  114. "強力なユニットを隠し持っていた。好きな組織専用ユニットを1つ獲得する。",
  115. "大金を手に入れた。キャラクター全員、アフターフェイズに配布される経験点が3増加する。",
  116. ]
  117. ),
  118. }.freeze
  119. 1 register_prefix('([+\d]+)*FF', TABLES.keys)
  120. end
  121. end
  122. end

lib/bcdice/game_system/FullMetalPanic.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/SRS'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class FullMetalPanic < SRS
  6. # ゲームシステムの識別子
  7. 1 ID = 'FullMetalPanic'
  8. # ゲームシステム名
  9. 1 NAME = 'フルメタル・パニック!RPG'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'ふるめたるはにつくRPG'
  12. # 固有のコマンドの接頭辞を設定する
  13. 1 register_prefix('2D6', 'MG', 'FP')
  14. # 成功判定のエイリアスコマンドを設定する
  15. 1 set_aliases_for_srs_roll('MG', 'FP')
  16. 1 HELP_MESSAGE = help_message()
  17. end
  18. end
  19. end

lib/bcdice/game_system/FutariSousa.rb

100.0% lines covered

100.0% branches covered

56 relevant lines. 56 lines covered and 0 lines missed.
24 total branches, 24 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class FutariSousa < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'FutariSousa'
  7. # ゲームシステム名
  8. 1 NAME = 'フタリソウサ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ふたりそうさ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定用コマンド
  14. 探偵用:【DT】…10面ダイスを2つ振って判定します。『有利』なら【3DT】、『不利』なら【1DT】を使います。
  15.     【DT6】…6面ダイスを2つ振って判定します。『有利』なら【3DT6】、『不利』なら【1DT6】を使います。
  16. 助手用:【AS】…6面ダイスを2つ振って判定します。『有利』なら【3AS】、『不利』なら【1AS】を使います。
  17.     【AS10】…10面ダイスを2つ振って判定します。『有利』なら【3AS10】、『不利』なら【1AS10】を使います。
  18. ・各種表
  19. 【セッション時】
  20. 異常な癖決定表      SHRD/新・異常な癖決定表   SHND
  21. 普通の?・異常な癖決定表 SHAD/ケイジ異常な癖決定表  SHKD
  22. 超探偵向け異常な癖表   SHLD
  23.  口から出る表    SHFM/強引な捜査表      SHBT/すっとぼけ表       SHPI
  24.  事件に夢中表    SHEG/パートナーと……表    SHWP/何かしている表      SHDS
  25.  奇想天外表     SHFT/急なひらめき表     SHIN/喜怒哀楽表        SHEM
  26.  人間エミュレート表 SHHE/人間エミュレート失敗表 SHHF/パートナーへのいたずら表 SHMP
  27.  思わせぶり表    SHSB/もどかしい表      SHFR/突然どうした表      SHIS
  28.  わがままを言う表  SHSE/普通に見える表     SHLM/嫉妬に狂う表       SHJS
  29.  傲慢な態度表    SHAR/比較的軽度なもの表   SHRM/ノータイム表       SHNT
  30.  捜査のやり方表   SHIM/貴族表         SHNO/説明しない表       SHNE
  31.  刑事としての癖表  SHHD/名誉ある探偵表     SHGD/超すごい表        SHSA
  32.  超事件に夢中表   SHEP/超パートナーと……表   SHXP
  33. イベント表
  34.  現場にて  EVS/なぜ?  EVW/協力者と共に EVN
  35.  向こうから EVC/VS容疑者 EVV
  36.  閉鎖空間  EVE
  37.  探偵のみ捜査 EVD/助手のみ捜査   EVA/観光捜査  EVT
  38.  思わぬヒント EVH/実験をしてみよう EVX/ゲスト捜査 EVG
  39.  ケイジ聞き込み捜査    EVQ/ケイジ大規模捜査      EVM/こっそり情報の受け渡し EVP
  40.  同僚たちと一緒に捜査する EVO/頻染みの店シチュエーション EVF/ハードBデカアクション EVB
  41.  探偵を大人しくさせる捜査 EVL/伝統的捜査         EVZ/原始的捜査       EVR
  42.  超探偵調査       EV6S/神速捜査         EV6F
  43. 感情表
  44.  感情表A/B   FLT66・FLT10
  45.  気に入っているところ  FLTL66 /気に入らないところ  FLTD66
  46.  ランダム感情決定表(あなた)  FLTRA
  47.  顔のパーツ     FLTF66/体のパーツ  FLTB66/生活習慣    FLTH66
  48.  ふわっとした感覚  FLTS66/他人への態度 FLTA66/ヘビーウェイト FLTW66
  49.  同僚     FLTC66/部下     FLTU66/上司     FLTO66
  50.  捜査のやり方 FLTI66
  51. 調査の障害表 OBT  変調表 ACT  目撃者表 EWT  迷宮入り表 WMT
  52. 思い出の品決定表 MIT  エピソード付き思い出の品表 MITE  呼び名表A・B  NCT66・NCT10
  53. 【設定時】
  54. 背景表
  55.  探偵 運命の血統 BGDD/天性の才能 BGDG/マニア     BGDM
  56.  助手 正義の人  BGAJ/情熱の人  BGAP/巻き込まれの人 BGAI
  57. 身長表 HT  たまり場表 BT  関係表 GRT
  58. 職業表A・B  JBT66・JBT10  ファッション特徴表A・B    FST66・FST10
  59. 好きなもの/嫌いなもの表A・B LDT66・LDT10
  60. MESSAGETEXT
  61. 1 def initialize(command)
  62. 270 super(command)
  63. 270 @d66_sort_type = D66SortType::ASC
  64. end
  65. 1 register_prefix('(\d+)?DT(?:6)?', '(\d+)?AS(?:10)?')
  66. 1 def eval_game_system_specific_command(command)
  67. 270 then: 39 if (m = /^(\d+)?DT(?:6)?$/i.match(command))
  68. 39 then: 24 else: 15 count = m[1]&.to_i || 2
  69. 39 else: 231 return roll_dt(command, count)
  70. 231 then: 33 else: 198 elsif (m = /^(\d+)?AS(?:10)?$/i.match(command))
  71. 33 then: 18 else: 15 count = m[1]&.to_i || 2
  72. 33 return roll_as(command, count)
  73. end
  74. 198 return roll_tables(command, self.class::TABLES)
  75. end
  76. 1 private
  77. # 成功の目標値
  78. 1 SUCCESS_THRESHOLD = 4
  79. # スペシャルとなる出目
  80. 1 SPECIAL_DICE = 6
  81. # 探偵用判定コマンド DT
  82. 1 def roll_dt(command, count)
  83. dice_list =
  84. 39 then: 13 if command =~ /^(\d*)DT6$/i
  85. 13 @randomizer.roll_barabara(count, 6)
  86. else: 26 else
  87. 26 @randomizer.roll_barabara(count, 10)
  88. end
  89. 39 max = dice_list.max
  90. result =
  91. 39 then: 6 if max <= 1
  92. 6 else: 33 Result.fumble(translate("FutariSousa.DT.fumble"))
  93. 33 then: 9 elsif dice_list.include?(SPECIAL_DICE)
  94. 9 else: 24 Result.critical(translate("FutariSousa.DT.special"))
  95. 24 then: 15 elsif max >= SUCCESS_THRESHOLD
  96. 15 Result.success(translate("success"))
  97. else: 9 else
  98. 9 Result.failure(translate("failure"))
  99. end
  100. 39 result.text = "#{command}(#{dice_list.join(',')}) > #{result.text}"
  101. 39 result
  102. end
  103. # 助手用判定コマンド AS
  104. 1 def roll_as(command, count)
  105. dice_list =
  106. 33 then: 11 if command =~ /^(\d*)AS10$/i
  107. 11 @randomizer.roll_barabara(count, 10)
  108. else: 22 else
  109. 22 @randomizer.roll_barabara(count, 6)
  110. end
  111. 33 max = dice_list.max
  112. result =
  113. 33 then: 6 if max <= 1
  114. 6 else: 27 Result.fumble(translate("FutariSousa.AS.fumble"))
  115. 27 then: 9 elsif dice_list.include?(SPECIAL_DICE)
  116. 9 else: 18 Result.critical(translate("FutariSousa.AS.special"))
  117. 18 then: 9 elsif max >= SUCCESS_THRESHOLD
  118. 9 Result.success(translate("FutariSousa.AS.success"))
  119. else: 9 else
  120. 9 Result.failure(translate("failure"))
  121. end
  122. 33 result.text = "#{command}(#{dice_list.join(',')}) > #{result.text}"
  123. 33 result
  124. end
  125. 1 class << self
  126. 1 private
  127. 1 def translate_tables(locale)
  128. {
  129. 2 "SHRD" => DiceTable::ChainTable.new(
  130. I18n.translate("FutariSousa.table.SHRD.name", locale: locale),
  131. "1D10",
  132. [
  133. DiceTable::Table.from_i18n("FutariSousa.table.SHFM", locale),
  134. DiceTable::Table.from_i18n("FutariSousa.table.SHBT", locale),
  135. DiceTable::Table.from_i18n("FutariSousa.table.SHPI", locale),
  136. DiceTable::Table.from_i18n("FutariSousa.table.SHEG", locale),
  137. DiceTable::Table.from_i18n("FutariSousa.table.SHWP", locale),
  138. DiceTable::Table.from_i18n("FutariSousa.table.SHDS", locale),
  139. DiceTable::Table.from_i18n("FutariSousa.table.SHIN", locale),
  140. DiceTable::Table.from_i18n("FutariSousa.table.SHEM", locale),
  141. DiceTable::Table.from_i18n("FutariSousa.table.SHFT", locale),
  142. I18n.translate("FutariSousa.table.SHRD.items", locale: locale)[9],
  143. ]
  144. ),
  145. "SHND" => DiceTable::ChainTable.new(
  146. I18n.translate("FutariSousa.table.SHND.name", locale: locale),
  147. "1D6",
  148. [
  149. DiceTable::Table.from_i18n("FutariSousa.table.SHHE", locale),
  150. DiceTable::Table.from_i18n("FutariSousa.table.SHHF", locale),
  151. DiceTable::Table.from_i18n("FutariSousa.table.SHMP", locale),
  152. DiceTable::Table.from_i18n("FutariSousa.table.SHSB", locale),
  153. DiceTable::Table.from_i18n("FutariSousa.table.SHFR", locale),
  154. DiceTable::Table.from_i18n("FutariSousa.table.SHIS", locale),
  155. ]
  156. ),
  157. "SHAD" => DiceTable::ChainTable.new(
  158. I18n.translate("FutariSousa.table.SHAD.name", locale: locale),
  159. "1D6",
  160. [
  161. DiceTable::Table.from_i18n("FutariSousa.table.SHSE", locale),
  162. DiceTable::Table.from_i18n("FutariSousa.table.SHLM", locale),
  163. DiceTable::Table.from_i18n("FutariSousa.table.SHJS", locale),
  164. DiceTable::Table.from_i18n("FutariSousa.table.SHAR", locale),
  165. DiceTable::Table.from_i18n("FutariSousa.table.SHRM", locale),
  166. DiceTable::Table.from_i18n("FutariSousa.table.SHNT", locale),
  167. ]
  168. ),
  169. "SHKD" => DiceTable::ChainTable.new(
  170. I18n.translate("FutariSousa.table.SHKD.name", locale: locale),
  171. "1D6",
  172. [
  173. DiceTable::Table.from_i18n("FutariSousa.table.SHIM", locale),
  174. DiceTable::Table.from_i18n("FutariSousa.table.SHNO", locale),
  175. DiceTable::Table.from_i18n("FutariSousa.table.SHNE", locale),
  176. DiceTable::Table.from_i18n("FutariSousa.table.SHHD", locale),
  177. I18n.translate("FutariSousa.table.SHKD.items", locale: locale)[4],
  178. I18n.translate("FutariSousa.table.SHKD.items", locale: locale)[5],
  179. ]
  180. ),
  181. "SHLD" => DiceTable::ChainTable.new(
  182. I18n.translate("FutariSousa.table.SHLD.name", locale: locale),
  183. "1D6",
  184. [
  185. DiceTable::Table.from_i18n("FutariSousa.table.SHGD", locale),
  186. DiceTable::Table.from_i18n("FutariSousa.table.SHSA", locale),
  187. DiceTable::Table.from_i18n("FutariSousa.table.SHEP", locale),
  188. DiceTable::Table.from_i18n("FutariSousa.table.SHXP", locale),
  189. I18n.translate("FutariSousa.table.SHLD.items", locale: locale)[4],
  190. I18n.translate("FutariSousa.table.SHLD.items", locale: locale)[5],
  191. ]
  192. ),
  193. "SHFM" => DiceTable::Table.from_i18n("FutariSousa.table.SHFM", locale),
  194. "SHBT" => DiceTable::Table.from_i18n("FutariSousa.table.SHBT", locale),
  195. "SHPI" => DiceTable::Table.from_i18n("FutariSousa.table.SHPI", locale),
  196. "SHEG" => DiceTable::Table.from_i18n("FutariSousa.table.SHEG", locale),
  197. "SHWP" => DiceTable::Table.from_i18n("FutariSousa.table.SHWP", locale),
  198. "SHDS" => DiceTable::Table.from_i18n("FutariSousa.table.SHDS", locale),
  199. "SHFT" => DiceTable::Table.from_i18n("FutariSousa.table.SHFT", locale),
  200. "SHIN" => DiceTable::Table.from_i18n("FutariSousa.table.SHIN", locale),
  201. "SHEM" => DiceTable::Table.from_i18n("FutariSousa.table.SHEM", locale),
  202. "SHHE" => DiceTable::Table.from_i18n("FutariSousa.table.SHHE", locale),
  203. "SHHF" => DiceTable::Table.from_i18n("FutariSousa.table.SHHF", locale),
  204. "SHMP" => DiceTable::Table.from_i18n("FutariSousa.table.SHMP", locale),
  205. "SHSB" => DiceTable::Table.from_i18n("FutariSousa.table.SHSB", locale),
  206. "SHFR" => DiceTable::Table.from_i18n("FutariSousa.table.SHFR", locale),
  207. "SHIS" => DiceTable::Table.from_i18n("FutariSousa.table.SHIS", locale),
  208. "SHSE" => DiceTable::Table.from_i18n("FutariSousa.table.SHSE", locale),
  209. "SHLM" => DiceTable::Table.from_i18n("FutariSousa.table.SHLM", locale),
  210. "SHJS" => DiceTable::Table.from_i18n("FutariSousa.table.SHJS", locale),
  211. "SHAR" => DiceTable::Table.from_i18n("FutariSousa.table.SHAR", locale),
  212. "SHRM" => DiceTable::Table.from_i18n("FutariSousa.table.SHRM", locale),
  213. "SHNT" => DiceTable::Table.from_i18n("FutariSousa.table.SHNT", locale),
  214. "SHIM" => DiceTable::Table.from_i18n("FutariSousa.table.SHIM", locale),
  215. "SHNO" => DiceTable::Table.from_i18n("FutariSousa.table.SHNO", locale),
  216. "SHNE" => DiceTable::Table.from_i18n("FutariSousa.table.SHNE", locale),
  217. "SHHD" => DiceTable::Table.from_i18n("FutariSousa.table.SHHD", locale),
  218. "SHGD" => DiceTable::Table.from_i18n("FutariSousa.table.SHGD", locale),
  219. "SHSA" => DiceTable::Table.from_i18n("FutariSousa.table.SHSA", locale),
  220. "SHEP" => DiceTable::Table.from_i18n("FutariSousa.table.SHEP", locale),
  221. "SHXP" => DiceTable::Table.from_i18n("FutariSousa.table.SHXP", locale),
  222. "EVS" => DiceTable::Table.from_i18n("FutariSousa.table.EVS", locale),
  223. "EVW" => DiceTable::Table.from_i18n("FutariSousa.table.EVW", locale),
  224. "EVN" => DiceTable::Table.from_i18n("FutariSousa.table.EVN", locale),
  225. "EVC" => DiceTable::Table.from_i18n("FutariSousa.table.EVC", locale),
  226. "EVV" => DiceTable::Table.from_i18n("FutariSousa.table.EVV", locale),
  227. "EVE" => DiceTable::Table.from_i18n("FutariSousa.table.EVE", locale),
  228. "EVD" => DiceTable::Table.from_i18n("FutariSousa.table.EVD", locale),
  229. "EVA" => DiceTable::Table.from_i18n("FutariSousa.table.EVA", locale),
  230. "EVT" => DiceTable::Table.from_i18n("FutariSousa.table.EVT", locale),
  231. "EVH" => DiceTable::Table.from_i18n("FutariSousa.table.EVH", locale),
  232. "EVX" => DiceTable::Table.from_i18n("FutariSousa.table.EVX", locale),
  233. "EVG" => DiceTable::Table.from_i18n("FutariSousa.table.EVG", locale),
  234. "EVQ" => DiceTable::Table.from_i18n("FutariSousa.table.EVQ", locale),
  235. "EVM" => DiceTable::Table.from_i18n("FutariSousa.table.EVM", locale),
  236. "EVP" => DiceTable::Table.from_i18n("FutariSousa.table.EVP", locale),
  237. "EVO" => DiceTable::Table.from_i18n("FutariSousa.table.EVO", locale),
  238. "EVF" => DiceTable::Table.from_i18n("FutariSousa.table.EVF", locale),
  239. "EVB" => DiceTable::Table.from_i18n("FutariSousa.table.EVB", locale),
  240. "EVL" => DiceTable::Table.from_i18n("FutariSousa.table.EVL", locale),
  241. "EVZ" => DiceTable::Table.from_i18n("FutariSousa.table.EVZ", locale),
  242. "EVR" => DiceTable::Table.from_i18n("FutariSousa.table.EVR", locale),
  243. "EV6S" => DiceTable::Table.from_i18n("FutariSousa.table.EV6S", locale),
  244. "EV6F" => DiceTable::Table.from_i18n("FutariSousa.table.EV6F", locale),
  245. "OBT" => DiceTable::D66Table.from_i18n("FutariSousa.table.OBT", locale),
  246. "ACT" => DiceTable::Table.from_i18n("FutariSousa.table.ACT", locale),
  247. "EWT" => DiceTable::Table.from_i18n("FutariSousa.table.EWT", locale),
  248. "WMT" => DiceTable::Table.from_i18n("FutariSousa.table.WMT", locale),
  249. "BGDD" => DiceTable::Table.from_i18n("FutariSousa.table.BGDD", locale),
  250. "BGDG" => DiceTable::Table.from_i18n("FutariSousa.table.BGDG", locale),
  251. "BGDM" => DiceTable::Table.from_i18n("FutariSousa.table.BGDM", locale),
  252. "BGAJ" => DiceTable::Table.from_i18n("FutariSousa.table.BGAJ", locale),
  253. "BGAP" => DiceTable::Table.from_i18n("FutariSousa.table.BGAP", locale),
  254. "BGAI" => DiceTable::Table.from_i18n("FutariSousa.table.BGAI", locale),
  255. "HT" => DiceTable::Table.from_i18n("FutariSousa.table.HT", locale),
  256. "BT" => DiceTable::Table.from_i18n("FutariSousa.table.BT", locale),
  257. "GRT" => DiceTable::D66Table.from_i18n("FutariSousa.table.GRT", locale),
  258. "MIT" => DiceTable::D66Table.from_i18n("FutariSousa.table.MIT", locale),
  259. "MITE" => DiceTable::Table.from_i18n("FutariSousa.table.MITE", locale),
  260. "JBT66" => DiceTable::D66Table.from_i18n("FutariSousa.table.JBT66", locale),
  261. "JBT10" => DiceTable::Table.from_i18n("FutariSousa.table.JBT10", locale),
  262. "FST66" => DiceTable::D66Table.from_i18n("FutariSousa.table.FST66", locale),
  263. "FST10" => DiceTable::Table.from_i18n("FutariSousa.table.FST10", locale),
  264. "LDT66" => DiceTable::D66Table.from_i18n("FutariSousa.table.LDT66", locale),
  265. "LDT10" => DiceTable::Table.from_i18n("FutariSousa.table.LDT10", locale),
  266. "FLT66" => DiceTable::D66Table.from_i18n("FutariSousa.table.FLT66", locale),
  267. "FLT10" => DiceTable::Table.from_i18n("FutariSousa.table.FLT10", locale),
  268. "FLTL66" => DiceTable::D66Table.from_i18n("FutariSousa.table.FLTL66", locale),
  269. "FLTD66" => DiceTable::D66Table.from_i18n("FutariSousa.table.FLTD66", locale),
  270. "FLTRA" => DiceTable::ChainTable.new(
  271. I18n.translate("FutariSousa.table.FLTRA.name", locale: locale),
  272. "1D6",
  273. [
  274. DiceTable::D66Table.from_i18n("FutariSousa.table.FLTF66", locale),
  275. DiceTable::D66Table.from_i18n("FutariSousa.table.FLTB66", locale),
  276. DiceTable::D66Table.from_i18n("FutariSousa.table.FLTH66", locale),
  277. DiceTable::D66Table.from_i18n("FutariSousa.table.FLTS66", locale),
  278. DiceTable::D66Table.from_i18n("FutariSousa.table.FLTA66", locale),
  279. DiceTable::D66Table.from_i18n("FutariSousa.table.FLTW66", locale),
  280. ]
  281. ),
  282. "FLTF66" => DiceTable::D66Table.from_i18n("FutariSousa.table.FLTF66", locale),
  283. "FLTB66" => DiceTable::D66Table.from_i18n("FutariSousa.table.FLTB66", locale),
  284. "FLTH66" => DiceTable::D66Table.from_i18n("FutariSousa.table.FLTH66", locale),
  285. "FLTS66" => DiceTable::D66Table.from_i18n("FutariSousa.table.FLTS66", locale),
  286. "FLTA66" => DiceTable::D66Table.from_i18n("FutariSousa.table.FLTA66", locale),
  287. "FLTW66" => DiceTable::D66Table.from_i18n("FutariSousa.table.FLTW66", locale),
  288. "FLTC66" => DiceTable::D66Table.from_i18n("FutariSousa.table.FLTC66", locale),
  289. "FLTU66" => DiceTable::D66Table.from_i18n("FutariSousa.table.FLTU66", locale),
  290. "FLTO66" => DiceTable::D66Table.from_i18n("FutariSousa.table.FLTO66", locale),
  291. "FLTI66" => DiceTable::D66Table.from_i18n("FutariSousa.table.FLTI66", locale),
  292. "NCT66" => DiceTable::D66Table.from_i18n("FutariSousa.table.NCT66", locale),
  293. "NCT10" => DiceTable::Table.from_i18n("FutariSousa.table.NCT10", locale),
  294. }
  295. end
  296. end
  297. 1 TABLES = translate_tables(:ja_jp)
  298. 1 register_prefix(TABLES.keys)
  299. end
  300. end
  301. end

lib/bcdice/game_system/FutariSousa_Korean.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/FutariSousa"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class FutariSousa_Korean < FutariSousa
  6. # ゲームシステムの識別子
  7. 1 ID = 'FutariSousa:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '둘이서 수사'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:둘이서 수사'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~MESSAGETEXT
  14. ・판정용 커맨드
  15. 탐정용:【DT】…10면체 주사위를 2개 굴려 판정합니다.『유리함』이라면【3DT】, 『불리함』이라면【1DT】를 사용합니다.
  16. 조수용:【AS】…6면체 주사위를 2개 굴려 판정합니다. 『유리함』이라면【3AS】, 『불리함』이라면【1AS】를 사용합니다.
  17.  
  18. ・각종표
  19. 【세션 시】
  20. 기벽 결정 표 SHRD
  21.  발언 표       SHFM/수사 강행 표     SHBT/시치미 표       SHPI
  22.  사건에 몰두 표    SHEG/파트너와…… 표     SHWP/뭔가 하고 있음 표   SHDS
  23.  기상천외 표     SHFT/갑작스런 영감 표    SHIN/희노애락 표      SHEM
  24.  인간 모방 표     SHHE/인간 모방 실패 표   SHHF/파트너를 향한 장난 표 SHMP
  25.  의미심장 표     SHSB/초조함 표       SHFR/갑자기 왜그래 표   SHIS
  26.  억지 요구 표    SHSE/멀쩡해 보임 표     SHLM/질투에 사로잡힘 표   SHJS
  27.  오만한 태도 표   SHAR/비교적 가벼운 행동 표 SHRM/노 타임 표      SHNT
  28.  수사 방식 표    SHIM/귀족 표        SHNO/설명하지 않음 표   SHNE
  29.  형사 특유의 습관 표 SHHD
  30.  
  31. 이벤트 표
  32.  현장에서 EVS/왜? EVW/협력자와 함께 EVN
  33.  알아서 찾아온 단서 EVC/VS용의자 EVV
  34.  폐쇄 공간 EVE
  35.  탐정 혼자 수사 EVD/조수 혼자 수사 EVA/관광 수사 EVT
  36.  예상치 못한 힌트 EVH/실험을 해보자 EVX/게스트 수사 EVG
  37.  형사 탐문 수사 EVQ/형사 대규모 수사 EVM/비밀스러운 정보 교환 EVP
  38.  동료들과 함께 수사 EVO/단골 가게 시추에이션 EVF/하드B 형사 액션 EVB
  39.  탐정을 얌전하게 만드는 수사 EVL/전통적 수사 EVZ/원시적 수사 EVR
  40.  
  41. 감정 표
  42.  감정 표A/B   FLT66・FLT10
  43.  마음에 드는 점  FLTL66 /마음에 안 드는 점  FLTD66
  44.  무작위 감정 결정 표(당친법)  FLTRA
  45.  얼굴 부위       FLTF66/신체 부위      FLTB66/생활 습관    FLTH66
  46.  마음이 들뜨는 감각   FLTS66/타인에 대한 태도  FLTA66/헤비 웨이트   FLTW66
  47.  동료          FLTC66/부하        FLTU66/상사     FLTO66
  48.  수사 방식 FLTI66
  49. 조사 방해 요인 표 OBT  상태 이상 표 ACT  목격자 표 EWT  미제 사건 표 WMT
  50. 추억의 물품 결정 표 MIT  에피소드 동반 추억의 물품 결정 표 MITE  
  51. 호칭 표A・B  NCT66・NCT10
  52.  
  53. 【설정】
  54. 배경 표
  55.  탐정 운명의 혈통  BGDD/천성적인 재능  BGDG/마니아   BGDM
  56.  조수 정의로운 사람 BGAJ/정열적인 사람  BGAP/말려든 사람 BGAI
  57. 신장 표 HT  아지트 표 BT  관계 표 GRT
  58. 직업 표A・B  JBT66・JBT10  패션 특징 표A・B  FST66・FST10
  59. 호불호 표A・B  LDT66・LDT10
  60. MESSAGETEXT
  61. 1 register_prefix_from_super_class()
  62. 1 def initialize(command)
  63. 113 super(command)
  64. 113 @locale = :ko_kr
  65. end
  66. 1 TABLES = translate_tables(:ko_kr)
  67. end
  68. end
  69. end

lib/bcdice/game_system/GURPS.rb

98.44% lines covered

90.0% branches covered

64 relevant lines. 63 lines covered and 1 lines missed.
20 total branches, 18 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class GURPS < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'GURPS'
  7. # ゲームシステム名
  8. 1 NAME = 'ガープス'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'かあふす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定においてクリティカル・ファンブルの自動判別、成功度の自動計算。(3d6<=目標値/目標値-3d6)
  14. ・祝福等のダイス目にかかる修正は「3d6-1<=目標値」といった記述で計算されます。(ダイス目の修正値はクリティカル・ファンブルに影響を与えません)
  15. ・クリティカル値・ファンブル値への修正については現在対応していません。
  16. ・クリティカル表 (CRT)
  17. ・頭部打撃クリティカル表 (HCRT)
  18. ・ファンブル表 (FMB)
  19. ・呪文ファンブル表 (MFMB)
  20. ・妖魔夜行スペシャルクリティカル表 (YSCRT)
  21. ・妖魔夜行スペシャルファンブル表 (YSFMB)
  22. ・妖術ファンブル表 (YFMB)
  23. ・命中部位表 (HIT)
  24. ・恐怖表 (FEAR+n)
  25.  nには恐怖判定の失敗度を入れてください。
  26. ・反応判定表 (REACT, REACT±n)
  27.  nには反応修正を入れてください。
  28. ・D66ダイスあり
  29. INFO_MESSAGE_TEXT
  30. 1 register_prefix('FEAR', 'REACT', '[\d\+\-]+\-3D6?[\d\+\-]*')
  31. 1 def initialize(command)
  32. 34 super(command)
  33. 34 @d66_sort_type = D66SortType::NO_SORT
  34. end
  35. # ゲーム別成功度判定(nD6)
  36. 1 def result_nd6(total, dice_total, dice_list, cmp_op, target)
  37. 20 then: 1 else: 19 return nil if target == "?"
  38. 19 else: 19 then: 0 return nil unless dice_list.size == 3 && cmp_op == :<=
  39. 19 success = target - total # 成功度
  40. 19 then: 5 if critical?(dice_total, target)
  41. 5 else: 14 Result.critical("クリティカル(成功度:#{success})")
  42. 14 then: 4 elsif fumble?(dice_total, target)
  43. 4 else: 10 Result.fumble("ファンブル(失敗度:#{success})")
  44. 10 then: 3 elsif dice_total >= 17
  45. 3 else: 7 Result.failure("自動失敗(失敗度:#{success})")
  46. 7 then: 4 elsif total <= target
  47. 4 Result.success("成功(成功度:#{success})")
  48. else: 3 else
  49. 3 Result.failure("失敗(失敗度:#{success})")
  50. end
  51. end
  52. 1 def eval_game_system_specific_command(command)
  53. 18 roll_3d6(command) || roll_fear(command) || roll_react(command) || roll_tables(command, TABLES)
  54. end
  55. 1 private
  56. 1 def critical?(dice_total, target)
  57. 19 (dice_total <= 6 && target >= 16) || (dice_total <= 5 && target >= 15) || dice_total <= 4
  58. end
  59. 1 def fumble?(dice_total, target)
  60. 14 (target - dice_total <= -10) || (dice_total >= 17 && target <= 15) || dice_total >= 18
  61. end
  62. 1 def roll_3d6(command)
  63. 18 m = /^([\d+-]+)-3D6?([\d+-]*)$/.match(command)
  64. 18 else: 4 then: 14 return nil unless m
  65. 4 target_number = ArithmeticEvaluator.eval(m[1])
  66. 4 modifier = ArithmeticEvaluator.eval(m[2])
  67. 4 formated_modifier = Format.modifier(modifier)
  68. 4 cmd = "3D6#{formated_modifier}<=#{target_number}"
  69. 4 return CommonCommand::AddDice.eval(cmd, self, @randomizer)
  70. end
  71. 1 def roll_fear(command)
  72. 14 m = /^FEAR(\+?\d+)?$/.match(command)
  73. 14 else: 2 then: 12 return nil unless m
  74. 2 modifier = m[1].to_i
  75. 2 dice = @randomizer.roll_sum(3, 6)
  76. 2 number = dice + modifier
  77. num =
  78. 2 then: 0 if number > 40
  79. 36
  80. else: 2 else
  81. 2 number - 4
  82. end
  83. 2 "恐怖表(#{number}) > #{FEAR_TABLE[num]}"
  84. end
  85. 1 FEAR_TABLE = [
  86. '1ターン朦朧状態。2ターン目に自動回復。',
  87. '1ターン朦朧状態。2ターン目に自動回復。',
  88. '1ターン朦朧状態。以後、毎ターン不利な修正を無視した意志判定を行い、成功すると回復。',
  89. '1ターン朦朧状態。以後、毎ターン不利な修正を無視した意志判定を行い、成功すると回復。',
  90. '1ターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  91. '1ターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  92. '1Dターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  93. '2Dターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  94. '思考不能。15ターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  95. '新たな癖をひとつ植え付けられる。',
  96. '1D点疲労。さらに1Dターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  97. '1D点疲労。さらに1Dターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  98. '新たな癖をひとつ獲得。さらに1Dターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  99. '1D分間意識を失う。以後、1分ごとに生命力判定を行い、成功すると回復。',
  100. '生命力判定を行い、失敗すると1点の負傷を受ける。さらに1D分間意識を失う。以後、1分ごとに生命力判定を行い、成功すると回復。',
  101. '1点負傷。2D分間意識を失う。以後、1分ごとに生命力判定を行い、成功すると回復。',
  102. '卒倒。4D分間意識不明。1D点疲労。',
  103. 'パニック。1D分間のあいだ、叫びながら走り回ったり、座り込んで泣きわめいたりする。以後、1分ごとに知力判定(修正なし)を行い、成功すると回復。',
  104. '-10CPの妄想を植え付けられる。',
  105. '-10CPの軽い恐怖症を植え付けられる。',
  106. '肉体的な変化。髪が真白になったり、老化したりする。-15CPぶんの肉体的特徴に等しい。',
  107. 'その恐怖に関連する軽い恐怖症を持っているならそれが強い恐怖症(CP2倍)になる。そうでなければ、-10CPぶんの精神的特徴を植え付けられる。',
  108. '-10CPの妄想を植え付けられる。生命力判定を行い、失敗すると1点の負傷を受ける。さらに1D分間意識を失う。以後、1分ごとに生命力判定を行い、成功すると回復。',
  109. '-10CPの軽い恐怖症を植え付けられる。生命力判定を行い、失敗すると1点の負傷を受ける。さらに1D分間意識を失う。以後、1分ごとに生命力判定を行い、成功すると回復。',
  110. '浅い昏睡状態。30分ごとに生命力判定を行い、成功すると目覚める。目覚めてから6時間はあらゆる判定に-2の修正。',
  111. '昏睡状態。1時間ごとに生命力判定を行い、成功すると目覚める。目覚めてから6時間はあらゆる判定に-2の修正。',
  112. '硬直。1D日のあいだ身動きしない。その時点で生命力判定を行い、成功すると動けるようになる。失敗するとさらに1D日硬直。その間、適切な医学的処置を受けていないかぎり、初日に1点、2日目に2点、3日目に3点と生命力を失っていく。動けるようになってからも、硬直していたのと同じ日数だけ、あらゆる判定に-2の修正。',
  113. '痙攣。1D分間地面に倒れて痙攣する。2D点疲労。また、生命力判定に失敗すると1D点負傷。これがファンブルなら生命力1点を永遠に失う。',
  114. '発作。軽い心臓発作を起こし、地面に倒れる。2D点負傷。',
  115. '大パニック。キャラクターは支離滅裂な行動に出る。GMが3Dを振り、目が大きければ大きいほど馬鹿げた行動を行う。その行動が終わったら知力判定を行い、成功すると我に返る。失敗すると新たな馬鹿げた行動をとる。',
  116. '強い妄想(-15CP)を植え付けられる。',
  117. '強い恐怖症、ないし-15CPぶんの精神的特徴を植え付けられる。',
  118. '激しい肉体的変化。髪が真白になったり、老化したりする。-20CPぶんの肉体的特徴に等しい。',
  119. '激しい肉体的変化。髪が真白になったり、老化したりする。-30CPぶんの肉体的特徴に等しい。',
  120. '昏睡状態。1時間ごとに生命力判定を行い、成功すると目覚める。目覚めてから6時間はあらゆる判定に-2の修正。さらに強い妄想(-15CP)を植え付けられる。',
  121. '昏睡状態。1時間ごとに生命力判定を行い、成功すると目覚める。目覚めてから6時間はあらゆる判定に-2の修正。さらに強い恐怖症、ないし-30CPぶんの精神的特徴を植え付けられる。',
  122. '昏睡状態。1時間ごとに生命力判定を行い、成功すると目覚める。目覚めてから6時間はあらゆる判定に-2の修正。さらに強い恐怖症、ないし-30CPぶんの精神的特徴を植え付けられる。知力が1点永遠に低下する。あわせて精神系の技能、呪文、超能力のレベルも低下する。',
  123. ].freeze
  124. 1 def roll_react(command)
  125. 12 m = /^REACT([+-]?\d*)$/.match(command)
  126. 12 else: 3 then: 9 return nil unless m
  127. 3 modifier = m[1].to_i
  128. 3 dice = @randomizer.roll_sum(3, 6)
  129. 3 number = dice + modifier
  130. 3 "反応表(#{number}) > #{reaction(number)}"
  131. end
  132. 1 def reaction(number)
  133. 25 REACTION_TABLE.find { |tuple| tuple.range.include?(number) }.text
  134. end
  135. 1 Tuple = Struct.new(:range, :text)
  136. REACTION_TABLE = [
  137. 1 [-Float::INFINITY..0, "最悪"],
  138. [1..3, "とても悪い"],
  139. [4..6, "悪い"],
  140. [7..9, "良くない"],
  141. [10..12, "中立"],
  142. [13..15, "良い"],
  143. [16..18, "とても良い"],
  144. [19..Float::INFINITY, "最高"],
  145. 8 ].map { |range, text| Tuple.new(range, text) }.freeze
  146. TABLES = {
  147. 1 "CRT" => DiceTable::Table.new(
  148. "クリティカル表",
  149. "3D6",
  150. [
  151. '体を狙っていたら、相手は気絶(回復は30分後に生命力判定)。他はダメージ3倍。',
  152. '相手の防御点を無視。',
  153. 'ダメージ3倍。',
  154. 'ダメージ2倍。',
  155. '相手は生命力判定を行い、失敗すると朦朧状態となる。',
  156. '四肢を狙っていたら、6ターンそこが使えなくなる。通常ダメージ。',
  157. '通常ダメージ。',
  158. '通常ダメージ。',
  159. '通常ダメージ。',
  160. '四肢を狙っていたら、6ターンそこが使えなくなる。通常ダメージ。',
  161. '相手の防御点を無視。',
  162. '四肢を狙っていたら、そこが使えなくなる(通常ダメージ)。他は2倍ダメージ。',
  163. '相手は武器を落とす。通常ダメージ。',
  164. 'ダメージ2倍。',
  165. 'ダメージ3倍。',
  166. '体を狙っていたら、相手は気絶(回復は30分後に生命力判定)。他はダメージ3倍。',
  167. ]
  168. ),
  169. "HCRT" => DiceTable::Table.new(
  170. "頭部打撃クリティカル表",
  171. "3D6",
  172. [
  173. '敵は即死する。',
  174. '敵は意識を失う。30分ごとに生命力判定をして、成功すると意識を回復する。',
  175. '敵は意識を失う。30分ごとに生命力判定をして、成功すると意識を回復する。',
  176. '敵は両目を負傷する。朦朧状態になる。目が見えないので、敏捷力-10。',
  177. '敵は片目を負傷する。朦朧状態になる。敏捷力-2。',
  178. '敵はバランスを失う。次のターンまで、防御しかできない。',
  179. '通常ダメージのみ。',
  180. '通常ダメージのみ。',
  181. '通常ダメージのみ。',
  182. '「叩き」攻撃なら、敵は24時間のあいだ耳が聞こえなくなる。「切り」「刺し」なら、1点しかダメージを与えられないが、傷跡が残る。',
  183. '「叩き」攻撃なら、敵は耳が聞こえなくなる。「切り」「刺し」なら、2点しかダメージを与えられないが、傷跡が残る。',
  184. '敵は逃げ腰になって武器を落とす(両手に武器を持っていたらランダムに決定)。',
  185. '敵は通常のダメージを受け、朦朧状態になる。',
  186. '敵は通常のダメージを受け、朦朧状態になる。',
  187. '敵は通常のダメージを受け、朦朧状態になる。',
  188. '敵は通常のダメージを受け、朦朧状態になる。',
  189. ]
  190. ),
  191. "FMB" => DiceTable::Table.new(
  192. "ファンブル表",
  193. "3D6",
  194. [
  195. '武器が壊れる。ただし、メイスなど固い"叩き"武器は壊れない(ふりなおし)。',
  196. '武器が壊れる。ただし、フレイルなど固い"叩き"武器は壊れない(ふりなおし)。',
  197. '自分の腕か足に命中(通常ダメージ)。ただし"刺し"武器や射撃ならふりなおし。',
  198. '自分の腕か足に命中(半分ダメージ)。ただし"刺し"武器や射撃ならふりなおし。',
  199. 'バランスを失い、次ターンは行動不可。次ターンの行動の番まで、能動防御-2。',
  200. '使った武器が非準備状態になる。1ターンよぶんに準備行動を行わないと、準備状態にならない。',
  201. '武器を落とす。',
  202. '武器を落とす。',
  203. '武器を落とす。',
  204. '使った武器が非準備状態になる。1ターンよぶんに準備行動を行わないと、準備状態にならない。',
  205. 'バランスを失い、次ターンは行動不可。次ターンの行動の番まで、能動防御-2。',
  206. '前か後ろ(ランダム)に武器が1メートル飛んでいく。その場にいるキャラクターは敏捷力判定を行い、失敗するとダメージ(通常の半分)を受ける。ただし、"刺し"武器や弓矢はその場に落ちるだけ。',
  207. '利き腕をくじいてしまう。30分間、攻撃にも防御にも使えない。',
  208. '足をすべらせ、その場に倒れる。',
  209. '武器が壊れる。ただし、モールなど固い"叩き"武器は壊れない(ふりなおし)。',
  210. '武器が壊れる。ただし、金属バットなど固い"叩き"武器は壊れない(ふりなおし)。',
  211. ]
  212. ),
  213. "MFMB" => DiceTable::Table.new(
  214. "呪文ファンブル表",
  215. "3D6",
  216. [
  217. '呪文が完全に失敗する。術者は1D点のダメージを受ける。',
  218. '呪文が術者にかかる。',
  219. '呪文が術者の仲間にかかる(対象はランダムに決定)。',
  220. '呪文が近くの敵にかかる(対象はランダムに決定)。',
  221. '哀れな物音があがり、硫黄のひどい匂いが立ち込める。',
  222. '呪文が目標以外のもの(仲間、敵、品物)にかかる。対象はランダムに決定するか、おもしろくなるようにGMが決定する。',
  223. '呪文が完全に失敗する。術者は1点のダメージを受ける。',
  224. '呪文が完全に失敗する。術者は朦朧状態になる(立ち直るには知力判定を行う)。',
  225. '大きな物音があがり、色とりどりの閃光が走る。',
  226. '見せ掛けの効果があらわれるが、弱くてとても役に立たない。',
  227. '意図した効果と逆の効果があらわれる。',
  228. '違った目標に、意図した効果とは逆の効果があらわれる(対象はランダムに決定)。',
  229. '何も起こらないが、術者は一時的にその呪文を忘れてしまう。思い出すまで、1週間ごとに知力判定を行う。',
  230. '呪文がかかったように思えるが、役に立たないただの見せかけだけ。',
  231. '呪文が完全に失敗し、術者の右腕が損なわれる。回復に1週間を要する。',
  232. '呪文が完全に失敗する。GMから見て、術者や呪文が純粋で善良なものでなければ、悪魔(第3版文庫版P.384参照)があらわれ、術者を攻撃する。',
  233. ]
  234. ),
  235. "YSCRT" => DiceTable::Table.new(
  236. "妖魔夜行スペシャルクリティカル表",
  237. "3D6",
  238. [
  239. '目(あるいは急所)に当たった!目(あるいは急所)が無ければ3倍ダメージ。',
  240. '胴体を狙っていたら、相手は気絶(回復は30分後に生命力判定)。他は3倍ダメージ。',
  241. '相手の防護点を無視。通常ダメージ。',
  242. 'ダメージ3倍。',
  243. 'ダメージ2倍',
  244. '敵は転倒する。通常ダメージ。',
  245. '四肢を狙っていたら、6ターンの間そこが使えなくなる。通常ダメージ。',
  246. '通常ダメージ。',
  247. '相手は武器を落とす。通常ダメージ。',
  248. '相手は生命力判定を行い、失敗すると朦朧状態になる。回復判定は毎ターンはじめに行う。通常ダメージ。',
  249. '相手の防護点を無視。通常ダメージ。',
  250. '四肢を狙っていたら、その四肢は使えなくなる(通常ダメージ)。他は2倍ダメージ。',
  251. '攻撃者は、目(あるいはその他の主要感覚部位)がくらんでしまう。1D-3ターン(最低1ターン)盲目状態。通常ダメージ。',
  252. 'ダメージ2倍。',
  253. 'ダメージ3倍。',
  254. '胴体を狙っていたら、相手は気絶(回復は30分後に生命力判定)。他は3倍ダメージ。',
  255. ]
  256. ),
  257. "YSFMB" => DiceTable::Table.new(
  258. "妖魔夜行スペシャルファンブル表",
  259. "3D6",
  260. [
  261. 'この表を2回振って、両方の結果を適用する。',
  262. '自分に命中。通常ダメージ。防護点、吸収、反射は無視(「◯◯に無敵」の妖力は有効)。',
  263. '自分に命中。半分ダメージ。防護点、吸収、反射は無視(「◯◯に無敵」の妖力は有効)。',
  264. '足などが傷つき、30分のあいだ、移動手段が失われる。能動防御-4。',
  265. '攻撃に使った部位に1D点のダメージ。防護点は無視。',
  266. 'バランスを失い、次ターンは行動不可。次ターンの行動の番まで、能動防御-2。',
  267. '攻撃に使った部位に1D-2点のダメージ。防護点は無視。',
  268. 'よろけてしまう。次のターンは移動できない。',
  269. 'バランスを失う。次のターンの行動の番まで、能動防御-2。',
  270. '足をすべらせその場に倒れる。飛行中なら50m落下(高度が50m以下なら墜落)。',
  271. '近くに味方(または無関係の人物)がいれば、攻撃が命中してしまう。いなければ、振り直し。',
  272. '大きな隙ができる。接近戦なら、敵は、即座に一撃をくわえられる。能動防御は-2で可能。射撃戦なら振り直し。',
  273. '攻撃に使った部位をくじいてしまう。30分間、攻撃にも防御にも使えない。',
  274. '攻撃者は、目(あるいはその他の主要感覚部位)がくらんでしまう。1D-3ターン(最低1ターン)盲目状態。通常ダメージ。',
  275. '自分に命中。半分ダメージ。防護点は無効。',
  276. 'この表を2回振って、プレイヤーが好きな方を適用する。',
  277. ]
  278. ),
  279. "YFMB" => DiceTable::Table.new(
  280. "妖術ファンブル表",
  281. "3D6",
  282. [
  283. '妖術が完全に失敗する。術者は3D点のダメージを受ける。',
  284. '妖術が完全に失敗する。術者は1D点のダメージを受ける。',
  285. '妖術が術者にかかる。',
  286. '妖術が術者の仲間にかかる(誰にかかるかは、ランダムに決定する)。',
  287. '妖術が近くの敵にかかる(誰にかかるかは、ランダムに決定する)。',
  288. '妖術が目標以外のもの(仲間、敵、品物)にかかる。何にかかるかは、ランダムに決定するか、おもしろくなるようにGMが選ぶ。',
  289. '妖術が発動したように見えるが、実際の効果はない。効果があったように見えても、GMがいちばん面白いと思った時に消滅させられる。',
  290. '妖術は発動するが、威力レベルが半分になっている。',
  291. '妖術は発動するが、威力レベルが半分になっている。さらに大きな音があがり、色とりどりの閃光が走り、悪臭(善い意図で使われたなら芳香)がたちこめる。',
  292. '妖術が完全に失敗する。術者は朦朧状態になる(立ち直るにはターンの頭ごとに意志判定を行う)。',
  293. '妖術は発動する。しかし制御することができない。次のターンでも、妖術を使ってしまうが、自動的にファンブルになる。',
  294. '目標に、意図した効果と正反対の効果があらわれる。',
  295. '何も怒らない。術者は一時的にその妖術を忘れてしまう。思い出すまで、1日ごとに知力判定を行う。',
  296. '違った目標に、意図した効果とは正反対の効果があらわれる(どこにあらわれるかはランダムに決定)。とっさに思いつかなければ"振り直す"。',
  297. '妖術が完全に失敗し、術者の弱点が明らかにされる。弱点がなければ振り直して良い。',
  298. '妖術が完全に失敗する。術者は完全な行動不能におちいる。回復は反日ごとに生命力で判定を行う。',
  299. ]
  300. ),
  301. "HIT" => DiceTable::Table.new(
  302. "命中部位表",
  303. "3D6",
  304. [
  305. '脳',
  306. '脳',
  307. '頭',
  308. '遠い腕',
  309. '手首(左右ランダム)',
  310. '近い腕',
  311. '胴体',
  312. '胴体',
  313. '胴体',
  314. '遠い足',
  315. '近い足',
  316. '近い足',
  317. '足首(左右ランダム)',
  318. '足首(左右ランダム)',
  319. '重要機関(胴体の)',
  320. '武器',
  321. ]
  322. ),
  323. }.freeze
  324. 1 register_prefix(TABLES.keys)
  325. end
  326. end
  327. end

lib/bcdice/game_system/Garactier.rb

99.18% lines covered

98.44% branches covered

122 relevant lines. 121 lines covered and 1 lines missed.
64 total branches, 63 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Garactier < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "Garactier"
  7. # ゲームシステム名
  8. 1 NAME = "ガラクティア"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "からくていあ"
  11. 1 HELP_MESSAGE = <<~TEXT
  12. ガラクティアVer1.04
  13. x:基準値
  14. y:目標値
  15. x, yについては四則演算の入力が可能
  16. ■達成値の算出(GRx)
  17. クリティカル・ファンブルの判定、達成値の表示を行う。
  18. ■通常判定(GRx>=y)
  19. 通常の判定を行う。
  20. ■命中判定(GRHx>=y)
  21. 命中判定を行う。
  22. ■回避判定(GRDx>=y)
  23. 回避判定を行う。
  24. ■抵抗判定(GRMx>=y)
  25. 抵抗判定を行う。
  26. ■探索成功マスレベル算出(GRSx)
  27. 探索・索敵判定時の最大成功マスレベル(ML)を算出する
  28. ■ 表
  29. アイテム決定表(ITMn)
  30. ランクnのアイテム表を振る。例)ITM2 ランク2アイテム表
  31. 上級アイテムの判定も行います。
  32. 命中部位決定表(BUI)
  33. 命中時の部位を決定します。
  34. 増強可能施設決定表(SST)
  35. 報告フェイズの増強可能施設を決定します。
  36. TEXT
  37. # アイテム用テーブル
  38. ITEM_TABLES = {
  39. 1 'ITM2' => DiceTable::D66Table.new(
  40. 'ランク2アイテム決定表',
  41. D66SortType::NO_SORT,
  42. {
  43. 11 => 'リペアスプレー',
  44. 12 => '防壁シャボン',
  45. 13 => '応援ボットちゃん',
  46. 14 => '偵察ボットちゃん',
  47. 15 => '回収ボットちゃん',
  48. 16 => 'ブラストチャージャー',
  49. 21 => '仕掛け爆弾',
  50. 22 => 'おなじみドリル',
  51. 23 => '清掃ボットちゃん',
  52. 24 => '突撃ボットちゃん',
  53. 25 => '修繕ボットちゃん',
  54. 26 => 'アンプリファイア',
  55. 31 => 'コバルトエール',
  56. 32 => 'カステラ',
  57. 33 => 'エアガン',
  58. 34 => '安全靴',
  59. 35 => 'ヘルメット',
  60. 36 => 'フラッシュバルブ',
  61. 41 => 'クリアワックス',
  62. 42 => '目薬',
  63. 43 => 'ラプチャーヒール',
  64. 44 => '防弾盾',
  65. 45 => 'プレートアーマー',
  66. 46 => 'ホーリーチャーム',
  67. 51 => 'カーネルシガー',
  68. 52 => 'ニトロギャンディー',
  69. 53 => '鉱樹の花飾り',
  70. 54 => 'アンプルシューター',
  71. 55 => 'メタル包帯',
  72. 56 => '炸裂発煙筒',
  73. 61 => 'シグナルドラッグ',
  74. 62 => '毒手',
  75. 63 => 'グルーガン',
  76. 64 => '縫い針',
  77. 65 => 'パイロン',
  78. 66 => '☆上級品☆',
  79. }
  80. ),
  81. 'ITM3' => DiceTable::D66Table.new(
  82. 'ランク3アイテム決定表',
  83. D66SortType::NO_SORT,
  84. {
  85. 11 => 'バナナ',
  86. 12 => 'イージーバズーカ',
  87. 13 => 'マルチバーニア',
  88. 14 => '赤い鉢巻き',
  89. 15 => 'カクテルポイズン',
  90. 16 => 'リペアジェル',
  91. 21 => '金砕棒',
  92. 22 => 'オシャレステッキ',
  93. 23 => '掃除機',
  94. 24 => 'ソーラーキャップ',
  95. 25 => 'タクティカルベスト',
  96. 26 => 'ホイッスル',
  97. 31 => 'パノラマバイザー',
  98. 32 => 'フリーズランチャー',
  99. 33 => 'オシャレスーツ',
  100. 34 => '暗器',
  101. 35 => '無限軌道',
  102. 36 => 'イルミネーション',
  103. 41 => '光線銃',
  104. 42 => '十手',
  105. 43 => '銅鑼',
  106. 44 => 'オシャレハット',
  107. 45 => '忍び足',
  108. 46 => '釣り竿',
  109. 51 => 'ブラックパウダー',
  110. 52 => 'ダーティーマント',
  111. 53 => 'バッテリーケイン',
  112. 54 => 'バンデッドショルダー',
  113. 55 => 'オシャレシューズ',
  114. 56 => 'サテライト',
  115. 61 => 'キーパーゴーレム',
  116. 62 => '混迷香',
  117. 63 => '応援旗',
  118. 64 => '黒子頭巾',
  119. 65 => 'バーナーランス',
  120. 66 => '☆上級品☆',
  121. }
  122. ),
  123. 'ITM4' => DiceTable::D66Table.new(
  124. 'ランク4アイテム決定表',
  125. D66SortType::NO_SORT,
  126. {
  127. 11 => '金塊',
  128. 12 => 'パラボラアンテナ',
  129. 13 => 'くらましの敷布',
  130. 14 => '無影灯',
  131. 15 => '油圧ショベル',
  132. 16 => 'マシンテール',
  133. 21 => '黒曜石の像',
  134. 22 => '黄金のクローバー',
  135. 23 => '朝霧の箒',
  136. 24 => 'ヘッドキャノン',
  137. 25 => 'レッグバルカン',
  138. 26 => 'ダイナモブロック',
  139. 31 => 'ジョウロ',
  140. 32 => 'スナイパーライフル',
  141. 33 => 'おてがるスコープ',
  142. 34 => 'ドーザーブレード',
  143. 35 => 'テツゲタ',
  144. 36 => 'ジェットスラスター',
  145. 41 => '宝剣',
  146. 42 => '指揮棒',
  147. 43 => '大兜',
  148. 44 => '妖精さん',
  149. 45 => 'ロングホーン',
  150. 46 => '鎖がま',
  151. 51 => '鳥籠',
  152. 52 => 'カタパルトアーム',
  153. 53 => 'スタンドマイク',
  154. 54 => '臆病なカカシ',
  155. 55 => 'ローラーダッシュ',
  156. 56 => 'モミジ',
  157. 61 => 'マスターキー',
  158. 62 => '隠れ蓑',
  159. 63 => '番傘',
  160. 64 => '駆動甲冑',
  161. 65 => '波紋の杖',
  162. 66 => '☆上級品☆',
  163. }
  164. ),
  165. 'ITM5' => DiceTable::D66Table.new(
  166. 'ランク5アイテム決定表',
  167. D66SortType::NO_SORT,
  168. {
  169. 11 => '因果の卵',
  170. 12 => 'ランプ',
  171. 13 => '常盤の琥珀',
  172. 14 => '新緑の冠',
  173. 15 => '萌芽の靴',
  174. 16 => '星の骸',
  175. 21 => '夜の帳',
  176. 22 => 'スリップブローチ',
  177. 23 => '拳法着',
  178. 24 => 'めがね',
  179. 25 => '白旗',
  180. 26 => 'ディラックナイフ',
  181. 31 => 'エレキドレッサー',
  182. 32 => 'ネイルガン',
  183. 33 => '木漏れ日のポプリ',
  184. 34 => 'ミスリルピッケル',
  185. 35 => 'デスマッチカフス',
  186. 36 => 'アダムスキースカート',
  187. 41 => '主砲',
  188. 42 => 'マイクロポッド',
  189. 43 => '樹皮の円盤',
  190. 44 => 'リンゴと蛇の紋章',
  191. 45 => 'セントリーガンナー',
  192. 46 => '化生の仮面',
  193. 51 => 'ガトリング',
  194. 52 => 'オカモチ',
  195. 53 => '芭蕉扇',
  196. 54 => 'ハッピートリガー',
  197. 55 => '蠢く湿布',
  198. 56 => 'メガホン',
  199. 61 => 'トランシーバー',
  200. 62 => '好奇の鋲',
  201. 63 => 'スレッジハンマー',
  202. 64 => 'セントール',
  203. 65 => 'ケーブルナイト',
  204. 66 => '☆上級品☆',
  205. }
  206. ),
  207. 'ITM6' => DiceTable::D66Table.new(
  208. 'ランク6アイテム決定表',
  209. D66SortType::NO_SORT,
  210. {
  211. 11 => '禍福の勾玉',
  212. 12 => '祭壇',
  213. 13 => 'ネジまき心臓',
  214. 14 => 'まどろみの頭蓋',
  215. 15 => '猛進拍車',
  216. 16 => '炉心結晶',
  217. 21 => '狂奔の鞭',
  218. 22 => '暁のベル',
  219. 23 => 'ネコシッポ',
  220. 24 => '鬼蜘蛛',
  221. 25 => '戦上手の脚',
  222. 26 => '薄絹の外套',
  223. 31 => 'ネコクロー',
  224. 32 => 'クライムチャンバー',
  225. 33 => '古の灯火',
  226. 34 => 'かしこい触手',
  227. 35 => 'オペラグラス',
  228. 36 => '大鉄拳',
  229. 41 => '妖刀',
  230. 42 => 'ヘビーライター',
  231. 43 => '緋緋色の針',
  232. 44 => 'バーサクシール',
  233. 45 => '光芒のアンクレット',
  234. 46 => 'ネコブーツ',
  235. 51 => '旅するコイン',
  236. 52 => '光子鏡壁',
  237. 53 => 'フェザージャケット',
  238. 54 => 'レーザーミニオン',
  239. 55 => 'マニピュレーター',
  240. 56 => 'ランパートシールド',
  241. 61 => '選定者の瞳',
  242. 62 => '打ち上げ花火',
  243. 63 => '魔笛',
  244. 64 => '指輪',
  245. 65 => 'ネコミミ',
  246. 66 => '☆上級品☆',
  247. }
  248. ),
  249. }.freeze()
  250. # 施設表
  251. SISETSU_TABLES = {
  252. 1 "SST" => DiceTable::Table.new(
  253. "増強可能施設決定表",
  254. "1D6",
  255. [
  256. '広場 マーケット 楽団',
  257. '広場 ガレージ 鉄工所',
  258. '広場 訓練場 農園 保健所',
  259. '広場 学舎 骨董屋',
  260. '広場 塗装工 菓子屋 貯蔵庫',
  261. '広場 診療所 礼拝堂',
  262. ]
  263. ),
  264. }.freeze
  265. # 部位表
  266. BUI_TABLES = {
  267. 1 "BUI" => DiceTable::Table.new(
  268. "命中部位決定表",
  269. "1D6",
  270. [
  271. '頭部',
  272. '胴体',
  273. '右腕',
  274. '左腕',
  275. '脚部',
  276. '任意部位',
  277. ]
  278. ),
  279. }.freeze
  280. 1 register_prefix('^GR[HDMS]?', 'ITM[2-6]', 'BUI', 'SST')
  281. 1 def eval_game_system_specific_command(command)
  282. 62 cmd_gr(command) ||
  283. roll_item(command) ||
  284. roll_tables(command, BUI_TABLES) ||
  285. roll_tables(command, SISETSU_TABLES)
  286. end
  287. # GR系コマンドの分割
  288. 1 def cmd_gr(command)
  289. 62 else: 27 case command
  290. when: 9 when /^GRS/
  291. 9 roll_search(command)
  292. when: 16 when /^GR[HDM]/
  293. 16 roll_target(command)
  294. when: 10 when /^GR/
  295. 10 roll_gr(command)
  296. end
  297. end
  298. # 探索・索敵判定
  299. 1 def roll_search(command)
  300. 9 m = %r{^GRS([+-/*\d]+)?$}.match(command)
  301. 9 else: 9 then: 0 unless m
  302. return nil
  303. end
  304. 9 modifier = Arithmetic.eval(m[1] || "", RoundType::FLOOR) || 0
  305. 9 dice_result = roll_dice_with_modifier(modifier)
  306. 9 r = determine_no_target_result("S", dice_result[:total], dice_result[:critical], dice_result[:fumble])
  307. 9 r.text = "(#{m[0]}) > #{dice_result[:dice_sum]}[#{dice_result[:dice_list].join(',')}]#{m[1]} > #{dice_result[:total]} > #{r.text}"
  308. 9 return r
  309. end
  310. # 目標値を持つ判定ロール
  311. 1 def roll_target(command)
  312. 16 m = %r{^GR([HDM])([+-/*\d]+)?(?:>=?([+-/*\d]+)+)$}.match(command)
  313. 16 else: 15 then: 1 unless m
  314. 1 return nil
  315. end
  316. 15 roll_type = m[1].to_str
  317. 15 modifier = Arithmetic.eval(m[2] || "", RoundType::FLOOR) || 0
  318. 15 target = Arithmetic.eval(m[3] || "", RoundType::FLOOR) || 0
  319. 15 dice_result = roll_dice_with_modifier(modifier)
  320. 15 r = determine_target_result(roll_type, dice_result[:total], target, dice_result[:critical], dice_result[:fumble])
  321. 15 r.text = "(#{m[0]}) > #{dice_result[:dice_sum]}[#{dice_result[:dice_list].join(',')}]#{m[2]} > #{dice_result[:total]} > #{r.text}"
  322. 15 return r
  323. end
  324. # GRのみの基本判定
  325. 1 def roll_gr(command)
  326. 10 m = %r{^GR([+-/*\d]+)?(>=)?\(?([+-/*\d]+)?\)?$}.match(command)
  327. 10 else: 9 then: 1 unless m
  328. 1 return nil
  329. end
  330. 9 modifier = Arithmetic.eval(m[1] || "", RoundType::FLOOR) || 0
  331. 9 target_flag = !m[2].nil?
  332. 9 dice_result = roll_dice_with_modifier(modifier)
  333. 9 then: 5 if target_flag
  334. 5 target = Arithmetic.eval(m[3] || "", RoundType::FLOOR) || 0
  335. 5 r = determine_target_result("", dice_result[:total], target, dice_result[:critical], dice_result[:fumble])
  336. else: 4 else
  337. 4 r = determine_no_target_result("", dice_result[:total], dice_result[:critical], dice_result[:fumble])
  338. end
  339. 9 r.text = "(#{m[0]}) > #{dice_result[:dice_sum]}[#{dice_result[:dice_list].join(',')}]#{m[1]} > #{dice_result[:total]} > #{r.text}"
  340. 9 return r
  341. end
  342. # 基準値(modifier)をもとに2d6+基準値の判定を行う
  343. 1 def roll_dice_with_modifier(modifier)
  344. 33 dice_list = randomizer.roll_barabara(2, 6)
  345. 33 dice_sum = dice_list.sum
  346. 33 total = dice_sum + modifier
  347. 33 critical_flag = dice_list.count(6) == 2
  348. 33 fumble_flag = dice_list.count(1) == 2
  349. 33 return {dice_list: dice_list, dice_sum: dice_sum, total: total, critical: critical_flag, fumble: fumble_flag}
  350. end
  351. # roll_typeごとにResultを作成(目標値あり)
  352. 1 def determine_target_result(roll_type, total, target, critical, fumble)
  353. 20 case roll_type
  354. when: 5 when "H"
  355. 5 then: 1 if critical
  356. 1 else: 4 Result.critical("クリティカル命中")
  357. 4 then: 1 elsif fumble
  358. 1 else: 3 Result.fumble("ファンブル")
  359. 3 then: 1 elsif total >= target + 4
  360. 1 else: 2 Result.success("急所命中")
  361. 2 then: 1 elsif total >= target
  362. 1 Result.success("命中")
  363. else: 1 else
  364. 1 Result.failure("失敗")
  365. end
  366. when: 6 when "D"
  367. 6 then: 1 if critical
  368. 1 else: 5 Result.critical("クリティカル")
  369. 5 then: 1 elsif fumble
  370. 1 else: 4 Result.fumble("ファンブル")
  371. 4 then: 1 elsif total >= target
  372. 1 else: 3 Result.success("回避成功")
  373. 3 then: 2 elsif total >= target - 4
  374. 2 Result.failure("半減命中")
  375. else: 1 else
  376. 1 Result.failure("失敗")
  377. end
  378. when "M"
  379. when: 4 # 抵抗判定は基準値以上(激情)のほうが悪い効果のことが多いためResultを反転[6,6]の場合にファンブル
  380. 4 then: 1 if critical
  381. 1 else: 3 Result.fumble("必ず激情")
  382. 3 then: 1 elsif fumble
  383. 1 else: 2 Result.critical("必ず平静")
  384. 2 then: 1 elsif total >= target
  385. 1 Result.failure("激情")
  386. else: 1 else
  387. 1 Result.success("平静")
  388. end
  389. else: 5 else
  390. 5 then: 1 if critical
  391. 1 else: 4 Result.critical("クリティカル")
  392. 4 then: 1 elsif fumble
  393. 1 else: 3 Result.fumble("ファンブル")
  394. 3 then: 1 elsif total >= target
  395. 1 Result.success("成功")
  396. else: 2 else
  397. 2 Result.failure("失敗")
  398. end
  399. end
  400. end
  401. # roll_typeごとにResultを作成(目標値なし)
  402. 1 def determine_no_target_result(roll_type, total, critical, fumble)
  403. 13 case roll_type
  404. when: 9 when "S"
  405. 9 then: 1 if critical
  406. 1 else: 8 Result.critical("クリティカル")
  407. 8 then: 1 elsif fumble
  408. 1 Result.fumble("ファンブル")
  409. else: 7 else
  410. 7 success_level = (total - 4) / 2
  411. 7 then: 3 if success_level >= 11
  412. 3 else: 4 success_level = 11
  413. 4 then: 1 else: 3 elsif success_level <= 0
  414. 1 success_level = 1
  415. end
  416. 7 r = Result.new
  417. 7 r.text = "成功ML #{success_level}"
  418. 7 return r
  419. end
  420. else: 4 else
  421. 4 then: 1 if critical
  422. 1 else: 3 Result.critical("クリティカル")
  423. 3 then: 1 elsif fumble
  424. 1 Result.fumble("ファンブル")
  425. else: 2 else
  426. 2 r = Result.new
  427. 2 r.text = "達成値 #{total}"
  428. 2 return r
  429. end
  430. end
  431. end
  432. ## アイテム表ロール ランク
  433. 1 def roll_item(command)
  434. 29 else: 15 then: 14 unless command.include?("ITM")
  435. 14 return nil
  436. end
  437. # 1回目のアイテムロール
  438. 15 result = roll_tables(command, ITEM_TABLES)
  439. # 上級判定
  440. 15 then: 10 else: 5 if result.include?("(66)")
  441. 10 result = roll_tables(command, ITEM_TABLES) + "*上級アイテム*"
  442. end
  443. # 選択判定
  444. 15 then: 5 else: 10 if result.include?("(66)")
  445. 5 result = "上級アイテムを自由選択!!"
  446. end
  447. 15 return result
  448. end
  449. end
  450. end
  451. end

lib/bcdice/game_system/Garako.rb

98.46% lines covered

91.67% branches covered

65 relevant lines. 64 lines covered and 1 lines missed.
24 total branches, 22 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/dice_table/table'
  3. 1 require 'bcdice/dice_table/range_table'
  4. 1 require 'bcdice/format'
  5. 1 module BCDice
  6. 1 module GameSystem
  7. 1 class Garako < Base
  8. # ゲームシステムの識別子
  9. 1 ID = 'Garako'
  10. # ゲームシステム名
  11. 1 NAME = 'ガラコと破界の塔'
  12. # ゲームシステム名の読みがな
  13. 1 SORT_KEY = 'からことはかいのとう'
  14. # ダイスボットの使い方
  15. 1 HELP_MESSAGE = <<~MESSAGETEXT
  16. ・判定 GR+n#f>=X (+n:判定値、#f:不安定による自動失敗基準値、X:目標値、それぞれ省略可能)
  17. ・部位決定チャート:HIT
  18. ・ダメージ+部位決定:GHAn(n:火力)
  19. ・ダメージチャート:xDCy(CDC/EDC/FDC/ADC/LDC )
  20. ・ダメージチャートver2:xDTy(CDT/EDT/FDT/ADT/LDT)
  21.  xは C:コックピット、E:エンジン、F:フレーム、A:アーム、L:レッグ
  22.  yはダメージ値
  23. 各種表
  24. ・個性表:IDI/動機決定表:MTV
  25. ・名前表
  26. ピグマー族  男:PNM 女:PNF  エレメント族 男:ENM 女:ENF
  27. ノーマッド族 男:NNM 女:NNF  ラット族   男:RNM 女:RNF
  28. ブレイン族  1:BN1 2:BN2  テンタクル族 1:TN1 2:TN2
  29. ・ガラコ改造チャート表:GCC
  30. ・武器改造チャート表:WCC
  31. ・イベントチャート表:EVC
  32. ・戦闘開始距離:BSD
  33. デフォルトダイス:10面
  34. MESSAGETEXT
  35. 1 def initialize(command)
  36. 52 super(command)
  37. 52 @sides_implicit_d = 10
  38. end
  39. # @param command [String]
  40. # @return [String, nil]
  41. 1 def eval_game_system_specific_command(command)
  42. 50 roll_tables(command, TABLES) ||
  43. roll_gr(command) ||
  44. roll_damage_chart(command) ||
  45. roll_attack_hit(command)
  46. end
  47. 1 private
  48. # 判定
  49. #
  50. # @param command [String]
  51. # @return [String, nil]
  52. 1 def roll_gr(command)
  53. 28 parser = Command::Parser.new("GR", round_type: round_type)
  54. .enable_fumble
  55. .restrict_cmp_op_to(nil, :>=)
  56. 28 cmd = parser.parse(command)
  57. 28 else: 10 then: 18 return nil unless cmd
  58. 10 modify_number = cmd.modify_number || 0
  59. 10 auto_failure_number = cmd.fumble || 1
  60. 10 target_number = cmd.target_number
  61. 10 dice = @randomizer.roll_once(10)
  62. 10 total = dice + modify_number
  63. result =
  64. 10 then: 2 if dice == 1
  65. 2 else: 8 "ファンブル"
  66. 8 then: 0 elsif dice <= auto_failure_number # 公式FAQより、ファンブルと自動失敗を区別する可能性があるので分岐
  67. else: 8 "自動失敗"
  68. 8 then: 2 elsif dice == 10
  69. 2 else: 6 "クリティカル"
  70. 6 then: 3 elsif target_number && total >= target_number
  71. 3 else: 3 "成功"
  72. 3 then: 2 else: 1 elsif target_number
  73. 2 "失敗"
  74. end
  75. 10 formated_modifier = Format.modifier(modify_number)
  76. 10 then: 0 else: 10 formated_auto_failure = "##{auto_failure_number}" if auto_failure_number >= 2
  77. 10 then: 7 else: 3 format_target = ">=#{target_number}" if target_number
  78. sequence = [
  79. 10 "(1D10#{formated_modifier}#{formated_auto_failure}#{format_target})",
  80. "#{dice}[#{dice}]#{formated_modifier}",
  81. total.to_s,
  82. result
  83. ]
  84. 10 return sequence.compact.join(" > ")
  85. end
  86. # ダメージ算出+部位決定チャート
  87. #
  88. # @param command [String]
  89. # @return [String, nil]
  90. 1 def roll_attack_hit(command)
  91. 3 m = /^GHA([-+\d]+)$/i.match(command)
  92. 3 else: 2 then: 1 return nil unless m
  93. 2 modifier = ArithmeticEvaluator.eval(m[1])
  94. 2 attack = @randomizer.roll_once(10)
  95. 2 total = attack + modifier
  96. 2 hit_text = "#{total}(ダメージを受けない)"
  97. 2 then: 1 else: 1 if total > 0
  98. 1 hit = TABLES["HIT"].roll(@randomizer)
  99. 1 hit_dice = ", HIT[#{hit.value}]"
  100. 1 hit_text = "#{hit.body}に #{total} -【部位装甲】"
  101. end
  102. 2 formated_modifier = Format.modifier(modifier)
  103. sequence = [
  104. 2 "(1D10#{formated_modifier})",
  105. "#{attack}[#{attack}]#{formated_modifier}#{hit_dice}",
  106. hit_text
  107. ]
  108. 2 return sequence.join(" > ")
  109. end
  110. # 部位ダメージチャート
  111. #
  112. # @param command [String]
  113. # @return [String, nil]
  114. 1 def roll_damage_chart(command)
  115. 18 m = /^([CEFAL]D[CT])([-+\d]+)$/i.match(command)
  116. 18 else: 15 then: 3 return nil unless m
  117. 15 chart = DAMAGE_CHARTS[m[1]]
  118. 15 damage = ArithmeticEvaluator.eval(m[2]).clamp(0, 10)
  119. 15 then: 2 else: 13 return "ダメージを受けない" if damage <= 0
  120. 13 result = chart[:table][damage - 1]
  121. 13 return "#{chart[:name]}(#{damage}) > #{result}"
  122. end
  123. DAMAGE_CHARTS = {
  124. 1 "CDC" => {
  125. name: "部位ダメージチャート:コックピット",
  126. table: [
  127. "小破(アーマー損傷):以後、この部位の【部位装甲】-1。",
  128. "小破(視界不良):モニターやハッチの歪み等により、視界を大きく遮られる。以後、【視認性】-1、【部位装甲】-1。",
  129. "小破(強震):大きく揺さぶられる。キミは【身体】10の判定を行う。失敗した場合、次のターンを失う。【部位装甲】-1。",
  130. "小破(収納直撃):アイテム収納スペースに直撃! 所持品一つにつき1d10を振れ。出目が5以下だった所持品は破壊される。【部位装甲】-1。",
  131. "中破(計器損傷):コンソールの一部が停止する。[弱体1]を受ける。",
  132. "中破(制御不能):コントロールが効かなくなる。キミは次のターンを失う。[弱体1]を受ける。",
  133. "中破(貫通!):パイロットに被害が! キミはHPダメージ(1d10-【身体】)に加え、[弱体1]を受ける。",
  134. "大破(故障):コックピットが完全にいかれる。キミは次のラウンド終了時まで、あらゆる判定に自動的にファンブルする。[弱体1]を受ける。",
  135. "大破(貫通!):パイロットに被害が! キミはHPダメージ(1d10+3-【身体】)に加え、[弱体1]を受ける。",
  136. "修復不能(破壊):コックピットが[修復不能]となる。キミは2d10-【身体】点のHPダメージを受ける。ガラコはすべての機能を停止する。コックピットのハッチが自動的に開く。",
  137. ]
  138. },
  139. "EDC" => {
  140. name: "部位ダメージチャート:エンジン",
  141. table: [
  142. "小破(アーマー損傷):以後、この部位の【部位装甲】-1。",
  143. "小破(アーマー損傷):以後、この部位の【部位装甲】-1。",
  144. "小破(燃料漏れ):タンクから燃料が漏れる。燃料-1。この部位の【部位装甲】-1。",
  145. "小破(燃料漏れ):タンクから燃料が漏れる。燃料-2。この部位の【部位装甲】-1。",
  146. "中破(エンジン不調):時々エンジンが動かなくなる。[弱体1]を受ける。",
  147. "中破(燃料漏れ):タンクから燃料が漏れる。燃料-2。[弱体1]を受ける。",
  148. "中破(ヒート):オーバーヒートする。次のターンの終了時まで、移動と攻撃を行えない。[弱体1]を受ける。",
  149. "大破(エンジン不調):キミは次のターンを失う。[弱体1]を受ける。",
  150. "大破(故障):以後、この部位の【部位装甲】が0になる。[弱体1]を受ける。",
  151. "修復不能(エンジン停止):エンジンが停止する。ガラコはすべての機能を停止する。コックピットのハッチが自動的に開く。【操作性】10の判定を行うこと。失敗するとエンジンが爆発する。その場合、すべての部位が[修復不能]となり、キミは2d10-【身体】点のダメージを受ける。",
  152. ]
  153. },
  154. "FDC" => {
  155. name: "部位ダメージチャート:フレーム",
  156. table: [
  157. "小破(不安定):体勢を崩す。次のターン、キミは攻撃を行えない。この部位の【部位装甲】-1。",
  158. "小破(スクラッチ!):フレームに醜い傷が残る。この部位の【部位装甲】-1。",
  159. "小破(アーマー損傷):フレームが歪む。この部位の【部位装甲】-1。",
  160. "小破(アーマー損傷):フレームがきしみ始め、ガラコの動きを阻害し始める。【移動力】-1。さらに、この部位の【部位装甲】-1。",
  161. "中破(放熱板損傷):熱を機体外に逃すことができなくなる。[弱体1]を受ける。",
  162. "中破(スタビライザー損傷):機体のバランス調整装置が故障する。【身体】10の判定を行うこと。失敗した場合、キミは次のターンを失う。[弱体1]を受ける。",
  163. "中破(貫通!):パイロットに被害が! キミはHPダメージ(1d10-【身体】)を受ける。[弱体1]を受ける。",
  164. "大破(停止):フレームが動かない。キミは次のターンを失う。[弱体1]を受ける。",
  165. "大破(アーマー損傷):フレームに甚大なダメージを受ける。以後、この部位の【部位装甲】に-3。[弱体1]を受ける。",
  166. "修復不能(フレーム崩壊):フレームが[修復不能]となる。フレームの大部分が剥がれ落ち、ガラコの内部が晒される。以後、キミに対して部位狙いが行われる場合、その命中判定に対する修正(p21)は発生しなくなる。[弱体2]を受ける。",
  167. ]
  168. },
  169. "ADC" => {
  170. name: "部位ダメージチャート:アーム",
  171. table: [
  172. "小破(アーマー損傷):アームの装甲にヒビが入る。【部位装甲】-1。",
  173. "小破(武器落とし!):【身体】8の判定を行う。失敗した場合、ダメージを受けた側のアームに(スロットを消費して)装着していた武器を落とす。【部位装甲】-1。",
  174. "小破(マニュピレータ損傷):指が何本かちぎれ飛んだ。【操作性】-1、【部位装甲】-1。",
  175. "小破(機能停止):次のターンの終了時まで、このアームを使った攻撃はできない。以後、この部位の【部位装甲】-1。",
  176. "中破(痙攣):アームの動きがぶれ始める。[弱体1]を受ける。",
  177. "中破(武器落とし!):ダメージを受けた側のアームに(スロットを消費して)装着していた武器を落とす。[弱体1]を受ける。",
  178. "中破(スピン):機体が大きく回転する。【身体】10の判定を行うこと。失敗した場合、[伏せ]状態となった上、次のターンを失う。[弱体1]を受ける。",
  179. "大破(アーマー損傷):以後、この部位の【部位装甲】を-3。[弱体1]を受ける。",
  180. "大破(武器落とし!):ダメージを受けた側のアームに(スロットを消費して)装着していた武器を落とす。以後、この部位の【部位装甲】が0になる。[弱体1]を受ける。",
  181. "修復不能(破壊):ダメージを受けた側のアームが[修復不能]となる。[弱体2]を受ける。",
  182. ]
  183. },
  184. "LDC" => {
  185. name: "部位ダメージチャート:レッグ",
  186. table: [
  187. "小破(アーマー損傷):以後、この部位の【部位装甲】-1。",
  188. "小破(よろめき):以後、この部位の【部位装甲】-1。次のターン終了時まで、キミは移動できない。",
  189. "小破(スネア):足元をすくわれる。【部位装甲】-1。さらに【身体】8の判定を行うこと。失敗した場合、キミは[伏せ]状態になる。",
  190. "小破(跛足):以後、【移動力】-1、【部位装甲】-1。",
  191. "中破(シャフト損傷):脚部の軸に歪みが生じる。[弱体1]を受ける。",
  192. "中破(アクチュエータ損傷):脚部のアクチュエータに大きな損傷を受ける。【移動力】-1。[弱体1]を受ける。",
  193. "中破(スピン):機体が大きく回転する。【身体】10の判定を行うこと。失敗した場合、[伏せ]状態となった上、次のターンを失う。[弱体1]を受ける。",
  194. "大破(アーマー損傷):以後、この部位の【部位装甲】を-3。[弱体1]を受ける。",
  195. "大破(跛足):以後、【移動力】-2。この部位の【部位装甲】が0になる。[弱体1]を受ける。",
  196. "修復不能(破壊):ダメージを受けた側のレッグが[修復不能]となる。【移動力】-2。[弱体2]を受ける。",
  197. ]
  198. },
  199. "CDT" => {
  200. name: "部位ダメージチャートv2: コックピット",
  201. table: [
  202. "アーマー損傷(小破/弱体0/装甲ダメージ1)装甲に軽いひび割れが走る。",
  203. "視界不良(小破/弱体0/装甲ダメージ1)モニターやハッチの歪み等により、視界を大きく遮られる。以後、【視認性】-1。",
  204. "強震(小破/弱体0/装甲ダメージ1)大きく揺さぶられる。キミは【身体】10 の判定を行なう。失敗した場合、次のターンを失う。",
  205. "貫通!(小破/弱体0/装甲ダメージ1)パイロットに被害が!キミはHPダメージ(1d10-【身体】)を受ける。",
  206. "計器損傷(中破/弱体1/装甲ダメージ1)コンソールの一部が停止する。",
  207. "制御不能(中破/弱体1/装甲ダメージ1)コントロールが効かなくなる。キミは次のターンを失う。",
  208. "貫通!(中破/弱体1/装甲ダメージ1)パイロットに被害が!キミはHPダメージ(1d10-【身体】)を受ける。",
  209. "故障(大破/弱体1/装甲ダメージ2)コックピットが完全にいかれる。キミは次のラウンド終了時まで、あらゆる判定に自動的にファンブルする。",
  210. "貫通!(大破/弱体1/装甲ダメージ2)パイロットに被害が!キミはHPダメージ(1d10+3-【身体】)を受ける。",
  211. "破壊(修復不能/弱体2/装甲ダメージ3)コックピットが「修復不能」となる。キミは2d10-【身体】点のHPダメージを受ける。ガラコはすべての機能を停止する。コックピットのハッチが自動的に開く。",
  212. ]
  213. },
  214. "EDT" => {
  215. name: "部位ダメージチャートv2: エンジン",
  216. table: [
  217. "アーマー損傷(小破/弱体0/装甲ダメージ1)装甲に軽いひび割れが走る。",
  218. "アーマー損傷(小破/弱体0/装甲ダメージ1)装甲に軽いひび割れが走る。",
  219. "燃料漏れ(小破/弱体0/装甲ダメージ1)タンクから燃料が漏れる。燃料-1。",
  220. "燃料漏れ(小破/弱体0/装甲ダメージ1)タンクから燃料が漏れる。燃料-2。",
  221. "エンジン不調(中破/弱体1/装甲ダメージ1)エンジンの調子が安定しない。",
  222. "オーバーヒート(中破/弱体1/装甲ダメージ1)オーバーヒートする。次のターンの終了時まで、移動と攻撃を行えない。",
  223. "エンジン不調(中破/弱体1/装甲ダメージ1)なんだか調子悪い。キミは次のターンを失う。",
  224. "燃料漏れ(大破/弱体1/装甲ダメージ2)タンクから燃料が漏れる。燃料-3。",
  225. "貫通!(大破/弱体1/装甲ダメージ2)パイロットに被害が!キミはHPダメージ(1d10+3-【身体】)を受ける。",
  226. "エンジン停止(修復不能/弱体2/装甲ダメージ3)エンジンが停止する。ガラコはすべての機能を停止する。コックピットのハッチが自動的に開く。【操作性】10の判定を行なうこと。失敗するとエンジンが爆発する。その場合、すべての部位が[修復不能]となり、キミは2d10-【身体】点のHPダメージを受ける",
  227. ]
  228. },
  229. "FDT" => {
  230. name: "部位ダメージチャートv2: フレーム",
  231. table: [
  232. "アーマー損傷 (小破 /0/装甲ダメージ1)装甲に軽いひび割れが走る。",
  233. "スクラッチ!(小破/弱体0/装甲ダメージ1)フレームに醜い傷が残る。",
  234. "歪み(小破/弱体0/装甲ダメージ1)フレームが歪み、ガラコの動きを阻害し始める。【移動力】-1。",
  235. "ハードポイント損傷(小破/弱体0/装甲ダメージ1)このフレームに装着している武器、及びオプションをすべて落とす。装着していた武器やオプションが外れかかる。キミは【身体】8の判定を行なう。失敗した場合、",
  236. "放熱板損傷(中破/弱体1/装甲ダメージ1)熱を機体外に逃すことができなくなる。これはヤバい。",
  237. "スタビライザー損傷(中破/弱体1/装甲ダメージ1)ターンを失う。機体のバランス調整装置が故障する。【身体】10の判定を行なうこと。失敗した場合、キミは次の",
  238. "貫通!(中破/弱体1/装甲ダメージ1)パイロットに被害が!キミはHPダメージ(1d10-【身体】)を受ける。",
  239. "停止(大破/弱体1/装甲ダメージ2)フレームが動かない。キミは次のターンを失う。",
  240. "ハードポイント破壊(大破/弱体1/装甲ダメージ2)武器やオプションを取り付ける箇所が破壊される。以後、このフレームに(スロットを消費して)装着している武器やオプションは使用できない(常時効果のあるものも、効果を失う)。",
  241. "フレーム崩壊(修復不能/弱体2/装甲ダメージ3)フレームが「修復不能」となる。フレームの大部分が剥がれ落ち、ガラコの内部が晒される。以後キミに対して部位狙いが行われる場合、その命中判定に対する修正(『GHT』p21)は発生しない。",
  242. ]
  243. },
  244. "ADT" => {
  245. name: "部位ダメージチャートv2: アーム",
  246. table: [
  247. "アーマー損傷(小破/弱体0/装甲ダメージ1)装甲に軽いひび割れが走る。",
  248. "武器落とし!(小破/弱体0/装甲ダメージ1)キミは【身体】8の判定を行う。失敗した場合、ダメージを受けた側のアームに(スロットを消費して)装着していた武器を落とす。",
  249. "マニピュレータ損傷(小破/弱体0/装甲ダメージ1)指が何本かちぎれ飛んだ。【操作性】-1。",
  250. "機能停止(小破/弱体0/装甲ダメージ1)次のターンの終了時まで、このアームを使った攻撃はできない。",
  251. "痙攣(中破/弱体1/装甲ダメージ1)アームの動きがぶれ始める。",
  252. "武器落とし!(中破/弱体1/装甲ダメージ1)ダメージを受けた側のアームに(スロットを消費して)装着していた武器を落とす。",
  253. "スピン(中破/弱体1/装甲ダメージ1)機体が大きく回転する。【身体】10の判定を行うこと。失敗した場合、[伏せ]状態となった上、次のターンを失う。",
  254. "武器落とし!(大破/弱体1/装甲ダメージ2)ダメージを受けた側のアームに(スロットを消費して)装着していた武器を落とす。",
  255. "ハードポイント破壊(大破/弱体1/装甲ダメージ2)している武器やオプションは使用できない(常時効果のあるものも、効果を失う)。武器やオプションを取り付ける箇所が破壊される。以後、このアームに(スロットを消費して)装着している武器やオプションは使用できない(常時効果のあるものも、効果を失う)。",
  256. "破壊(修復不能/2/装甲ダメージ3)ダメージを受けた側のアームが「修復不能」となる。",
  257. ]
  258. },
  259. "LDT" => {
  260. name: "部位ダメージチャートv2: レッグ",
  261. table: [
  262. "アーマー損傷 (小破 /弱体0/装甲ダメージ1)装甲に軽いひび割れが走る。",
  263. "よろめき (小破 /弱体0/装甲ダメージ1)次のターンの終了時まで、キミは移動できない。",
  264. "スネア (小破 /弱体0/装甲ダメージ1)足元をすくわれる。【身体】8 の判定を行うこと。失敗した場合、キミは[伏せ]状態になる。",
  265. "跛足 (小破 /弱体0/装甲ダメージ1)以後、【移動力】-1。",
  266. "シャフト損傷 (中破 /弱体1/装甲ダメージ1)脚部の軸に歪みが生じる。",
  267. "アクチュエータ損傷 (中破 /弱体1/装甲ダメージ1)脚部のアクチュエータに大きな損傷を受ける。【移動力】-1。",
  268. "スピン (中破 /弱体1/装甲ダメージ1)機体が大きく回転する。【身体】10 の判定を行うこと。失敗した場合、[伏せ]状態となった上、次のターンを失う。",
  269. "跛足 (大破 /弱体1/装甲ダメージ2)以後、【移動力】-2。",
  270. "ハードポイント破壊 (大破 /弱体1/装甲ダメージ2)している武器やオプションは使用できない(常時効果のあるものも、効果を失う)。 武器やオプションを取り付ける箇所が破壊される。以後、このレッグに(スロットを消費して)装着している武器やオプションは使用できない(常時効果のあるものも、効果を失う)。",
  271. "破壊 (修復不能 /弱体2/装甲ダメージ3)ダメージを受けた側のレッグが「修復不能」となる。【移動力】-2。",
  272. ]
  273. }
  274. }.freeze
  275. TABLES = {
  276. 1 "PNM" => DiceTable::Table.new(
  277. "名前表:ピグマー族(男)",
  278. "1D10",
  279. [
  280. "バビロン",
  281. "グリニッジ",
  282. "デトロイト",
  283. "ヨコスカ",
  284. "ボルドー",
  285. "テキサス",
  286. "シチリア",
  287. "チェルノブイリ",
  288. "グンマ",
  289. "サマルトリア",
  290. ]
  291. ),
  292. "PNF" => DiceTable::Table.new(
  293. "名前表:ピグマー族(女)",
  294. "1D10",
  295. [
  296. "ルアンダ",
  297. "ローマ",
  298. "フロリダ",
  299. "ホノルル",
  300. "ツガル",
  301. "ゲルニカ",
  302. "シャンハイ",
  303. "モナコ",
  304. "チグリス",
  305. "オーサカ",
  306. ]
  307. ),
  308. "ENM" => DiceTable::Table.new(
  309. "名前表:エレメント族(男)",
  310. "1D10",
  311. [
  312. "アポロン",
  313. "ミキストリ",
  314. "アザゼル",
  315. "フマクト",
  316. "マサカド",
  317. "ククルカン",
  318. "ルシフェル",
  319. "ザギグ",
  320. "フェムト",
  321. "マイトレーヤ",
  322. ]
  323. ),
  324. "ENF" => DiceTable::Table.new(
  325. "名前表:エレメント族(女)",
  326. "1D10",
  327. [
  328. "クシナダ",
  329. "アルテミス",
  330. "ゼノビア",
  331. "フレイヤ",
  332. "イシュタム",
  333. "ベルゼバブ",
  334. "マイシェラ",
  335. "バステト",
  336. "スクルド",
  337. "アテナ",
  338. ]
  339. ),
  340. "NNM" => DiceTable::Table.new(
  341. "名前表:ノーマッド族(男)",
  342. "1D10",
  343. [
  344. "ドラム",
  345. "カホン",
  346. "ハレルヤ",
  347. "トリノウタ",
  348. "スリラー",
  349. "シンバル",
  350. "リュート",
  351. "ウクレレ",
  352. "タンバリン",
  353. "ユメコウネン",
  354. ]
  355. ),
  356. "NNF" => DiceTable::Table.new(
  357. "名前表:ノーマッド族(女)",
  358. "1D10",
  359. [
  360. "ピアノ",
  361. "テルミン",
  362. "ソバカス",
  363. "イマジン",
  364. "ツナミ",
  365. "ピッコロ",
  366. "ハープ",
  367. "シャミセン",
  368. "ミザルー",
  369. "ドナドナ",
  370. ]
  371. ),
  372. "RNM" => DiceTable::Table.new(
  373. "名前表:ラット族(男)",
  374. "1D10",
  375. [
  376. "ポチ",
  377. "シシマル",
  378. "ポンタ",
  379. "コテツ",
  380. "アルフォンス",
  381. "パトラッシュ",
  382. "ミッキー",
  383. "ジジ",
  384. "サカモト",
  385. "オンソクマル",
  386. ]
  387. ),
  388. "RNF" => DiceTable::Table.new(
  389. "名前表:ラット族(女)",
  390. "1D10",
  391. [
  392. "タマ",
  393. "ココ",
  394. "ラブ",
  395. "ピーコ",
  396. "モカ",
  397. "オリガミ",
  398. "ヒメ",
  399. "ミィ",
  400. "ルナ",
  401. "ク・メル",
  402. ]
  403. ),
  404. "BN1" => DiceTable::Table.new(
  405. "名前表:ブレイン族(その1)",
  406. "1D10",
  407. [
  408. "マリファナ",
  409. "バファリン",
  410. "タミフル",
  411. "セーロガン",
  412. "モルヒネ",
  413. "ハルシオン",
  414. "トリカブト",
  415. "バイアグラ",
  416. "エリクサー",
  417. "クラレ",
  418. ]
  419. ),
  420. "BN2" => DiceTable::Table.new(
  421. "名前表:ブレイン族(その2)",
  422. "1D10",
  423. [
  424. "ニトロ",
  425. "ダイオキシン",
  426. "タウリン",
  427. "コイーバ",
  428. "マールボロ",
  429. "キャメル",
  430. "ドクダミ",
  431. "アブサン",
  432. "ドブロク",
  433. "マティーニ",
  434. ]
  435. ),
  436. "TN1" => DiceTable::Table.new(
  437. "名前表:テンタクル族(その1)",
  438. "1D10",
  439. [
  440. "アップル",
  441. "プリン",
  442. "ビフテキ",
  443. "ガンモ",
  444. "レバニラ",
  445. "カボチャ",
  446. "コロッケ",
  447. "マトン",
  448. "ギョーザ",
  449. "タバスコ",
  450. ]
  451. ),
  452. "TN2" => DiceTable::Table.new(
  453. "名前表:テンタクル族(その2)",
  454. "1D10",
  455. [
  456. "キノコ",
  457. "セロリ",
  458. "ラザニア",
  459. "ユドーフ",
  460. "ニンジン",
  461. "カイワレ",
  462. "ボルシチ",
  463. "ハクサイ",
  464. "キャラメル",
  465. "ワタアメ",
  466. ]
  467. ),
  468. "MTV" => DiceTable::Table.new(
  469. "動機決定表",
  470. "1D10",
  471. [
  472. "金。お宝の臭いがした。",
  473. "正義。破界の塔は災いのもと。絶たねばならない。",
  474. "友情。この破界の塔のせいで友人が困っている。助けなくちゃ。",
  475. "探究心。破界の塔のことをもっと知りたい。",
  476. "戦闘狂。もっと戦いたい。",
  477. "暇つぶし。退屈な日常を忘れたい。",
  478. "自殺願望。なんかもう死にたい。",
  479. "冒険家。ワクワクしたい。",
  480. "山男。シティが肌に合わない。",
  481. "特に動機らしい動機はない。",
  482. ]
  483. ),
  484. "HIT" => DiceTable::Table.new(
  485. "部位決定チャート",
  486. "1D10",
  487. [
  488. "コックピット",
  489. "エンジン",
  490. "フレーム",
  491. "フレーム",
  492. "フレーム",
  493. "フレーム",
  494. "ライトアーム",
  495. "レフトアーム",
  496. "ライトレッグ",
  497. "レフトレッグ",
  498. ]
  499. ),
  500. "GCC" => DiceTable::Table.new(
  501. "ガラコ改造チャート表",
  502. "1D10",
  503. [
  504. "【命中+】価格+200。【操作性】+1。[不安定]1。",
  505. "【回避+】価格+200。【機動性】+1。[不安定]1。",
  506. "【視界+】価格+200。【視認性】+2。[不安定]1。",
  507. "【移動+】価格+100。【移動力】+1。",
  508. "【火力+】価格+200。その部位に装着した武器の火力を常に+2する。",
  509. "【部位装甲+】価格+100。【部位装甲】+2。",
  510. "【限界重量+】価格+100。【限界重量】+1000。",
  511. "【安定性+】価格+50。[不安定]-1。",
  512. "【スロット+】価格+500。【スロット】+1。",
  513. "【弱体無効】価格+500。このパーツへの部位ダメージによる[弱体]の効果を無視する。",
  514. ]
  515. ),
  516. "WCC" => DiceTable::Table.new(
  517. "武器改造チャート表",
  518. "1D10",
  519. [
  520. "【命中+】価格+200。【操作性】+1。",
  521. "【火力+】価格+200。【火力】+2。",
  522. "【射程】価格+200。【射程】+3。「射程:近接」の場合、「射程:3 or 近接」となる(攻撃する度にどちらかを選ぶ)。",
  523. "【範囲+】価格+200。1シーンにつき1回、この武器の目標を「範囲2」に変更してもよい(フリーアクション)。もともと範囲攻撃できる武器の場合は、「範囲n+1」にできる(1シーン1回、フリーアクション)。",
  524. "【部位変更】価格+200。装着できる部位がランダムに追加される。部位決定チャート(『GHT』p21)を使用して決めること。",
  525. "【部位装甲+】価格+100。装着した部位の【部位装甲】+2。",
  526. "【精度+】価格+100。この武器を使って狙い撃ちをする場合、命中判定に+1。",
  527. "【装飾+】価格+500。特に効果はないが、売却した時の金額が上昇する。",
  528. "【幸運+】価格+500。この武器による命中判定の出目が1だった場合、判定を振り直しても良い(1シーン1回まで)。",
  529. "【回数無限】価格+500。武器の使用回数制限がなくなる。",
  530. ]
  531. ),
  532. "EVC" => DiceTable::Table.new(
  533. "イベントチャート表",
  534. "1D10",
  535. [
  536. "【クリーチャー】スタートル(『GTD』p30)が1d10+3体現れる。戦闘開始。",
  537. "【ビット】コーンノーズ(『GTD』p23)が1d10+3体現れる。戦闘開始。",
  538. "【ノーマッド】ノーマッド族のランドクローラーと遭遇する。このシーンはノーマッドからアイテムを購入しても良い。ノーマッド族は天蓋都市で購入できるすべてのアイテムを販売している(ただし金額は20%増し)。",
  539. "【ピグマー族】君達の目的地方面から、ボロボロになったピグマー族のNPCが歩いてくる。NPCに何があったのかはGMが決めよ。ピグマー族を天蓋都市まで送った場合、謝礼として200クレジットを受け取ることが出来る。NPCは重量50のアイテムとして扱う。",
  540. "【ビット】ダスクウォッチ(『GTD』p23)が1d10+3体現れる。戦闘開始。",
  541. "【異常気象】嵐、竜巻、豪雨など、異常な気象によって行動を阻害される。PCのうち代表者1名が【視認】10の判定を行うこと。失敗した場合、次のシーンはスポットを移動できない。現在のスポットに留まることになる。",
  542. "【クリーチャー】ナグ(『GTD』p31)が1d10+4体現れる。戦闘開始。",
  543. "【ビット】ランオーバー(『GTD』p25)が3体現れる。戦闘開始。",
  544. "【猛毒の霧】付近に毒の霧が立ち込める。全てのキャラクターは毒によって1d10のHPダメージを受ける。",
  545. "【最悪の敵】ズルワーン(『GTD』p29)が1体現れる。戦闘開始。",
  546. ]
  547. ),
  548. "BSD" => DiceTable::Table.new(
  549. "戦闘開始距離",
  550. "1D10",
  551. [
  552. "3マス",
  553. "3マス",
  554. "6マス",
  555. "6マス",
  556. "9マス",
  557. "9マス",
  558. "12マス",
  559. "12マス",
  560. "15マス",
  561. "15マス",
  562. ]
  563. ),
  564. 'IDI' => DiceTable::RangeTable.new(
  565. "個性表",
  566. "1D100",
  567. [
  568. [1..5, '〈近接武器熟練〉 近接攻撃の火力+1。'],
  569. [6..10, '〈遠隔武器熟練〉 遠隔攻撃の火力+1。'],
  570. [11..15, '〈天才〉 【技術】+1。'],
  571. [16..20, '〈頑強〉 【身体】+1。'],
  572. [21..25, '〈早業〉 【速度】+1。'],
  573. [26..30, '〈スイフトフット〉 【移動力】+1。'],
  574. [31..35, '〈超反応〉 行動判定値+2。'],
  575. [36..40, '〈警戒心〉 罠を発見するための判定に+2。'],
  576. [41..45, '〈解除屋〉 罠を解除するための判定に+2。'],
  577. [46..50, '〈タフガイ〉 最大HP+5。'],
  578. [51, '〈踏み込み〉 キミが使用する近接武器のデータを「射程:2」に変更する。'],
  579. [52, '〈不動〉 キミは強制移動の効果を受けない。'],
  580. [53, '〈ペイローダー〉 ガラコの【限界重量】+2000。'],
  581. [54, '〈魅力〉 キミがHPを回復するアイテム、もしくは超能力の目標になった時、キミのHPを追加で1点回復する。'],
  582. [55, '〈ダブルタップ〉 キミのターン開始時に使用。このターンの間、キミは追加で1回の遠隔攻撃を行うことができる。'],
  583. [56, '〈薙ぎ払い〉 キミのターン開始時に使用。このターンの間、キミが行う近接攻撃の目標を「周囲1マス以内にいるすべての敵」に変更する。'],
  584. [57, '〈武器落とし〉 キミは部位ひとつを指定する。目標は指定された部位に(スロットを消費して)装着している武器すべてを地面に落とす。'],
  585. [58, '〈切り払い〉 キミが行う回避判定の直前に使用。その判定を、【機動性】ではなく【操作性】で判定してよい。ただし、キミは近接武器を装着していなければならない。'],
  586. [59, '〈体崩しの達人〉 キミが目標のレッグに攻撃を命中させる度、その目標は【機動性】10の判定を行う。失敗した場合、目標は[伏せ]状態になる。'],
  587. [60, '〈超分解術〉 アイテムひとつを目標にする。目標のアイテムの重量を1/4にする。ただし、そのアイテムは使用できなくなる。再度〈超分解術〉の判定に成功することで、元に戻せる(重量が元に戻り、アイテムが使用可能になる)。'],
  588. [61, '〈即時換装〉 キミは、ガラコのパーツ換装を(ベースアクションではなく)ムーブアクションで行ってもよい。'],
  589. [62, '〈ノックバック〉 キミが目標に5点以上の最終ダメージを与えた直後に使用。目標を1マス、任意の方向に強制移動させる。近接武器で攻撃した場合のみ使用できる。'],
  590. [63, '〈照準〉 このターンの間、次に行う攻撃の命中判定+1。'],
  591. [64, '〈燃料節約術〉 戦闘時以外、キミは燃料を消費しなくてよい。'],
  592. [65, '〈追撃〉 キミの敵が、隣接するマスから離れるような移動を宣言した直後に使用。キミはその敵に対して近接攻撃を行う。近接攻撃の後、敵は移動を行うこと。'],
  593. [66, '〈連撃〉 キミが敵の部位を[修復不能]にした直後に使用。キミは再度、その敵に対して攻撃を行う。'],
  594. [67, '〈殺し屋〉 キミがコックピットに攻撃を命中させる度、そのガラコの操縦者は2点のHPを失う。'],
  595. [68, '〈極大射程〉 キミが扱う遠隔武器の射程を2倍にする。'],
  596. [69, '〈援護射撃〉 目標が回避判定を行った直後に使用。目標の回避判定の達成値-1。その後、キミは準備済みの遠隔武器ひとつの使用回数を1減らすこと。'],
  597. [70, '〈鉄壁〉 キミがダメージを受けた直後に使用。そのダメージを無効化する。'],
  598. [71, '〈心臓狙い〉 キミが部位狙いを行い、コックピット、もしくはエンジンに対して攻撃を行う際、命中判定+1。'],
  599. [72, '〈四肢狙い〉 キミが部位狙いを行い、アーム、もしくはレッグに対して攻撃を行う際、命中判定+1。'],
  600. [73, '〈窮地逆転〉 キミの判定の出目が1だった時、その出目を10に変更する。'],
  601. [74, '〈防御重視〉 ラウンド開始時に使用。【操作性】-1。【機動性】+2。ラウンド終了時まで。'],
  602. [75, '〈チアガール〉 目標は即座に追加のターンを得る。'],
  603. [76, '〈毒半減〉 キミが[毒]状態になった時、毎回失うHPを1点減らす。ノーマッド族はこの個性を取得できない。'],
  604. [77, '〈毒無効〉 キミは[毒]状態にならない。この個性はノーマッド族だけが取得できる。'],
  605. [78, '〈生存術〉 キミは各シーン終了時、HPを減らさなくてよい。'],
  606. [79, '〈平衡感覚〉 キミは[不安定]状態のペナルティを受けない。'],
  607. [80, '〈不屈〉 キミのターン開始時に使用。このターンの間、キミはガラコの損傷による[弱体]の効果を受けない。'],
  608. [81, '〈プレデターセンス〉 近接攻撃の命中判定+2。この個性はラット族だけが取得できる。'],
  609. [82, '〈鷹の目〉 遠隔攻撃の命中判定+2。この個性はラット族だけが取得できる。'],
  610. [83, '〈超リペア術〉 部位をひとつ選択する。目標の部位の被ダメージすべてを一時的に回復する(修復不能を除く)。回復したダメージは、シーン終了時に元に戻る(再度壊れる)。この個性はブレイン族のみが取得できる。'],
  611. [84, '〈浮遊術〉 キミは[飛行]状態になる。シーン終了時まで。この個性はテンタクル人のみが取得できる。'],
  612. [85, '〈瞬間移動術〉 キミは任意のマスに瞬間移動する。この個性はテンタクル人のみが取得できる。'],
  613. [86, '〈ハイボルテージ〉 4ラウンドめ以降、キミが持つすべての武器の火力を+2する。'],
  614. [87, '〈スライドディフェンス〉 キミが部位決定チャートを振った直後に使用。チャートの結果を+1する。'],
  615. [88, '〈カーブアタック〉 目標が部位決定チャートを振った直後に使用。チャートの結果を-1する。'],
  616. [89, '〈サイコショット〉 目標に[火力0]の攻撃を行う(自動命中)。(超能力)'],
  617. [90, '〈ファイア〉 目標に[火力5]の攻撃を行う。(超能力)'],
  618. [91, '〈アイス〉 目標に[火力3]の攻撃を行う。(超能力)'],
  619. [92, '〈サンダー〉 目標に[火力2]の攻撃を行う。(超能力)'],
  620. [93, '〈テレパシー〉 キミは念話によって会話することができる。(超能力)'],
  621. [94, '〈ミラー〉 目標が超能力の使用を宣言した直後に使用。超能力の目標を使用者自身に変更する。(超能力)'],
  622. [95, '〈バインド〉 目標のターン開始時に使用。目標の移動力-3。ターン終了時まで。(超能力)'],
  623. [96, '〈アーマー〉 目標のすべての部位装甲+2。シーン終了時まで。(超能力)'],
  624. [97, '〈バリア〉 目標がダメージを受けた直後に使用。ダメージを3点軽減する。(超能力)'],
  625. [98, '〈ヒール〉 目標のHPを[1d10-4]点回復する。出目が低いとHPを失う可能性があることに注意。(超能力)'],
  626. [99, '〈カース〉 目標が判定を行った直後に使用。その判定の達成値を-3する。'],
  627. [100, '〈リザレクション〉 死んだ目標を生き返らせる。生き返った目標のHPは10になる。このシーンの間に死亡したキャラクターのみ目標にできる。(超能力)'],
  628. ]
  629. )
  630. }.freeze
  631. 1 register_prefix('GR', '[CEFAL]D[CT]', 'GHA', TABLES.keys)
  632. end
  633. end
  634. end

lib/bcdice/game_system/GardenOrder.rb

98.44% lines covered

79.31% branches covered

64 relevant lines. 63 lines covered and 1 lines missed.
29 total branches, 23 branches covered and 6 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class GardenOrder < Base
  5. # ゲームシステムのの識別子
  6. 1 ID = 'GardenOrder'
  7. # ゲームシステム名
  8. 1 NAME = 'ガーデンオーダー'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'かあてんおおたあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・基本判定
  14.  GOx/y@z x:成功率、y:連続攻撃回数(省略可)、z:クリティカル値(省略可)
  15.  (連続攻撃では1回の判定のみが実施されます)
  16.  例)GO55 GO100/2 GO70@10 GO155/3@44
  17. ・負傷表
  18.  DCxxy
  19.  xx:属性(切断:SL,銃弾:BL,衝撃:IM,灼熱:BR,冷却:RF,電撃:EL)
  20.  y:ダメージ
  21.  例)DCSL7 DCEL22
  22. ・負傷表(ソウルエンコーダー用)
  23.  SExxy
  24.  xx:属性(切断:SL,銃弾:BL,衝撃:IM,灼熱:BR,冷却:RF,電撃:EL)
  25.  y:ダメージ
  26.  例)SESL7 SEEL22
  27. INFO_MESSAGE_TEXT
  28. 1 register_prefix(
  29. 'GO',
  30. 'DC(SL|BL|IM|BR|RF|EL).+',
  31. 'SE(SL|BL|IM|BR|RF|EL).+'
  32. )
  33. 1 def eval_game_system_specific_command(command)
  34. 52 else: 0 case command
  35. when: 34 when %r{GO(-?\d+)(/(\d+))?(@(\d+))?}i
  36. 34 success_rate = Regexp.last_match(1).to_i
  37. 34 repeat_count = (Regexp.last_match(3) || 1).to_i
  38. 34 critical_border_text = Regexp.last_match(5)
  39. 34 critical_border = get_critical_border(critical_border_text, success_rate)
  40. 34 return check_roll_repeat_attack(success_rate, repeat_count, critical_border)
  41. when: 18 when /^(DC|SE)(SL|BL|IM|BR|RF|EL)(\d+)/i
  42. 18 chart_type = Regexp.last_match(1)
  43. 18 type = Regexp.last_match(2)
  44. 18 damage_value = Regexp.last_match(3).to_i
  45. 18 else: 0 case chart_type
  46. when: 9 when "DC"
  47. 9 return look_up_damage_chart(type, damage_value)
  48. when: 9 when "SE"
  49. 9 return look_up_damage_se_chart(type, damage_value)
  50. end
  51. end
  52. return nil
  53. end
  54. 1 def get_critical_border(critical_border_text, success_rate)
  55. 120 else: 102 then: 18 return critical_border_text.to_i unless critical_border_text.nil?
  56. 102 critical_border = [success_rate / 5, 1].max
  57. 102 return critical_border
  58. end
  59. 1 def check_roll_repeat_attack(success_rate, repeat_count, critical_border)
  60. 107 success_rate_per_one = success_rate / repeat_count
  61. # 連続攻撃は最終的な成功率が50%以上であることが必要 cf. p217
  62. 107 then: 2 else: 105 if repeat_count > 1 && success_rate_per_one < 50
  63. 2 return "D100<=#{success_rate_per_one}@#{critical_border} > 連続攻撃は成功率が50%以上必要です"
  64. end
  65. 105 check_roll(success_rate_per_one, critical_border)
  66. end
  67. 1 def check_roll(success_rate, critical_border)
  68. 105 then: 3 else: 102 success_rate = 0 if success_rate < 0
  69. 105 then: 89 else: 16 fumble_border = (success_rate < 100 ? 96 : 99)
  70. 105 dice_value = @randomizer.roll_once(100)
  71. 105 result = get_check_result(dice_value, success_rate, critical_border, fumble_border)
  72. 105 result.text = "D100<=#{success_rate}@#{critical_border} > #{dice_value} > #{result.text}"
  73. 105 return result
  74. end
  75. 1 def get_check_result(dice_value, success_rate, critical_border, fumble_border)
  76. # クリティカルとファンブルが重なった場合は、ファンブルとなる。 cf. p175
  77. 118 then: 21 else: 97 return Result.fumble("ファンブル") if dice_value >= fumble_border
  78. 97 then: 32 else: 65 return Result.critical("クリティカル") if dice_value <= critical_border
  79. 65 then: 43 else: 22 return Result.success("成功") if dice_value <= success_rate
  80. 22 return Result.failure("失敗")
  81. end
  82. 1 def look_up_damage_chart(type, damage_value)
  83. 27 chart_type = "DC"
  84. 27 name, table = get_damage_table_info_by_type(type, chart_type)
  85. 27 row = get_table_by_number(damage_value, table, nil)
  86. 27 then: 0 else: 27 return nil if row.nil?
  87. 27 "負傷表:#{name}[#{damage_value}] > #{row[:damage]} | #{row[:name]} … #{row[:text]}"
  88. end
  89. 1 def look_up_damage_se_chart(type, damage_value)
  90. 9 chart_type = "SE"
  91. 9 name, table = get_damage_table_info_by_type(type, chart_type)
  92. 9 row = get_table_by_number(damage_value, table, nil)
  93. 9 then: 0 else: 9 return nil if row.nil?
  94. 9 "負傷表(#{chart_type}):#{name}[#{damage_value}] > #{row[:damage]} | #{row[:name]} … #{row[:text]}"
  95. end
  96. 1 def get_damage_table_info_by_type(type, chart_type)
  97. 36 data = {}
  98. 36 else: 0 case chart_type
  99. when: 27 when "DC"
  100. 27 data = DAMAGE_TABLE[type]
  101. when: 9 when "SE"
  102. 9 data = DAMAGE_TABLE_SE[type]
  103. end
  104. 36 then: 0 else: 36 return nil if data.nil?
  105. 36 return data[:name], data[:table]
  106. end
  107. DAMAGE_TABLE = {
  108. 1 "SL" => {
  109. name: "切断",
  110. table: [
  111. [5,
  112. {name: "切り傷",
  113. text: "皮膚が切り裂かれる。",
  114. damage: "軽傷1"}],
  115. [10,
  116. {name: "脚部負傷",
  117. text: "足が切り裂かれ、思わずひざまずく。",
  118. damage: "軽傷2/マヒ"}],
  119. [13,
  120. {name: "出血",
  121. text: "斬り裂かれた傷から出血が続く。",
  122. damage: "軽傷3/DOT:軽傷1"}],
  123. [16,
  124. {name: "胴部負傷",
  125. text: "胴部に大きな傷を受ける。",
  126. damage: "軽傷4"}],
  127. [19,
  128. {name: "腕部負傷",
  129. text: "腕に大きな傷を受ける。",
  130. damage: "重傷1/DOT:軽傷1"}],
  131. [22,
  132. {name: "腹部負傷",
  133. text: "腹部を深く切り裂かれる。",
  134. damage: "重傷2"}],
  135. [25,
  136. {name: "大量出血",
  137. text: "傷は深く、そこから大量に出血する。",
  138. damage: "重傷2/DOT:軽傷2"}],
  139. [28,
  140. {name: "裂傷",
  141. text: "治りにくい傷をつけられる。",
  142. damage: "重傷3"}],
  143. [31,
  144. {name: "視界不良",
  145. text: "頭部に受けた傷から血が流れ、視界がふさがれる。",
  146. damage: "重傷3/スタン"}],
  147. [34,
  148. {name: "胸部負傷",
  149. text: "胸から腰にかけて大きく切り裂かれる。",
  150. damage: "致命傷1"}],
  151. [37,
  152. {name: "動脈切断",
  153. text: "動脈が切り裂かれ、噴き出るように出血する。",
  154. damage: "致命傷1/DOT:軽傷3"}],
  155. [39,
  156. {name: "胸部切断",
  157. text: "傷が肺にまで達し、喀血する。",
  158. damage: "致命傷2"}],
  159. [9999,
  160. {name: "脊髄損傷",
  161. text: "脊髄が損傷する。",
  162. damage: "致命傷2/放心、スタン、マヒ"}],
  163. ]
  164. },
  165. "BL" => {
  166. name: "銃弾",
  167. table: [
  168. [5,
  169. {name: "腕部損傷",
  170. text: "銃弾が腕をかすめた。",
  171. damage: "軽傷2"}],
  172. [10,
  173. {name: "腕部貫通",
  174. text: "銃弾が腕を貫く。痛みはあるが動作に支障はない。",
  175. damage: "軽傷3"}],
  176. [13,
  177. {name: "胴部負傷",
  178. text: "胴部に銃弾をくらう。痛みで動きが鈍くなる。",
  179. damage: "軽傷4/スロウ:-3"}],
  180. [16,
  181. {name: "肩負傷",
  182. text: "肩を貫かれる。骨が砕けたようだ。",
  183. damage: "重傷1"}],
  184. [19,
  185. {name: "腹部負傷",
  186. text: "腹部が貫かれる。かろうじて内臓にダメージはないようだ。",
  187. damage: "重傷2"}],
  188. [22,
  189. {name: "脚部貫通",
  190. text: "脚を銃弾に貫かれ、その場でひざまずく。",
  191. damage: "重傷2/マヒ"}],
  192. [25,
  193. {name: "消化器系損傷",
  194. text: "胃などの消化器官にダメージを受ける。",
  195. damage: "重傷3"}],
  196. [28,
  197. {name: "盲管銃弾",
  198. text: "身体に弾丸が深々と刺さる。激痛が走る。",
  199. damage: "重傷3/スロウ:-5"}],
  200. [31,
  201. {name: "内臓損傷",
  202. text: "いくつかの内臓にダメージを受ける。",
  203. damage: "致命傷1/スタン"}],
  204. [34,
  205. {name: "胴部貫通",
  206. text: "腹部への攻撃が貫通し、出血する。",
  207. damage: "致命傷1/DOT:軽傷1"}],
  208. [37,
  209. {name: "胸部負傷",
  210. text: "銃弾で肺を貫かれる。",
  211. damage: "致命傷2"}],
  212. [39,
  213. {name: "致命的な一撃",
  214. text: "銃弾が頭部に命中。ショックで意識を飛ばされる。",
  215. damage: "致命傷2/放心"}],
  216. [9999,
  217. {name: "必殺の一撃",
  218. text: "銃弾が心臓の近くを貫く。動脈にダメージを受けたようだ。",
  219. damage: "致命傷2/DOT:重傷1"}],
  220. ]
  221. },
  222. "IM" => {
  223. name: "衝撃",
  224. table: [
  225. [5,
  226. {name: "打撲",
  227. text: "攻撃を受けた箇所がどす黒く腫れ上がる。",
  228. damage: "軽傷1"}],
  229. [10,
  230. {name: "転倒",
  231. text: "衝撃で転倒する。",
  232. damage: "軽傷1/マヒ"}],
  233. [13,
  234. {name: "平衡感覚喪失",
  235. text: "衝撃で三半規管にダメージを受ける。",
  236. damage: "軽傷2、疲労2"}],
  237. [16,
  238. {name: "ボディーブロー",
  239. text: "腹部に直撃。痛みが継続し、体力を奪う。",
  240. damage: "軽傷3/DOT:疲労3"}],
  241. [19,
  242. {name: "痛打",
  243. text: "胴部や脚部などに打撃を受ける。",
  244. damage: "軽傷4/スタン"}],
  245. [22,
  246. {name: "頭部痛打",
  247. text: "頭部にクリーンヒット。意識がもうろうとする。",
  248. damage: "軽傷5/放心"}],
  249. [25,
  250. {name: "脚部骨折",
  251. text: "攻撃が足に命中し、骨折する。",
  252. damage: "重傷1/スロウ:-5"}],
  253. [28,
  254. {name: "大転倒",
  255. text: "激しい衝撃によって、負傷すると共に大きく体勢を崩す。",
  256. damage: "重傷1/マヒ、スタン"}],
  257. [31,
  258. {name: "脳震盪",
  259. text: "脳が大きく揺さぶられ、意識が飛びそうになる。",
  260. damage: "重傷2/放心"}],
  261. [34,
  262. {name: "複雑骨折",
  263. text: "攻撃を受けた部分が大きくひしゃげ、複雑骨折したようだ。",
  264. damage: "重傷3/放心、スタン"}],
  265. [37,
  266. {name: "頭部裂傷",
  267. text: "頭部に命中。皮膚が大きく裂ける。",
  268. damage: "致命傷1、疲労3"}],
  269. [39,
  270. {name: "肋骨負傷",
  271. text: "折れた肋骨が肺に突き刺さり、まともに呼吸を行なうことができない。",
  272. damage: "致命傷1/放心、スタン"}],
  273. [9999,
  274. {name: "内臓損傷",
  275. text: "衝撃が身体の芯まで届き、内臓がいくつか傷ついたようだ。",
  276. damage: "致命傷2/DOT:重傷1"}],
  277. ]
  278. },
  279. "BR" => {
  280. name: "灼熱",
  281. table: [
  282. [5,
  283. {name: "火傷",
  284. text: "皮膚に小さな火傷を負う。",
  285. damage: "軽傷1"}],
  286. [10,
  287. {name: "温度上昇",
  288. text: "熱によって、怪我だけではなく体力も奪われる。",
  289. damage: "軽傷2、疲労1"}],
  290. [13,
  291. {name: "恐怖",
  292. text: "燃え上がる炎に恐怖を感じ、身体がすくんで動きが止まる。",
  293. damage: "軽傷3/放心"}],
  294. [16,
  295. {name: "発火",
  296. text: "衣服や身体の一部に火が燃え移る。",
  297. damage: "軽傷3/DOT:軽傷1"}],
  298. [19,
  299. {name: "爆発",
  300. text: "爆発により吹き飛ばされ、転倒する。",
  301. damage: "重傷1/マヒ"}],
  302. [22,
  303. {name: "大火傷",
  304. text: "痕が残るほどの大きな火傷を負う。",
  305. damage: "重傷2"}],
  306. [25,
  307. {name: "熱波",
  308. text: "火傷と強力な熱により意識がもうろうとする。",
  309. damage: "重傷2/スタン"}],
  310. [28,
  311. {name: "大爆発",
  312. text: "激しい爆発で吹き飛ばされ、ダメージと共に転倒する。",
  313. damage: "重傷3/マヒ"}],
  314. [31,
  315. {name: "大発火",
  316. text: "広範囲に火が燃え移る。",
  317. damage: "重傷3/DOT:軽傷1"}],
  318. [34,
  319. {name: "炭化",
  320. text: "高熱のあまり、焼けた部分が炭化してしまう。",
  321. damage: "致命傷1"}],
  322. [37,
  323. {name: "内臓火傷",
  324. text: "高温の空気を吸い込む、気道にも火傷を負ってしまう。",
  325. damage: "致命傷1/DOT:軽傷1"}],
  326. [39,
  327. {name: "全身火傷",
  328. text: "身体の各所に深い火傷を負う。",
  329. damage: "致命傷2"}],
  330. [9999,
  331. {name: "致命的火傷",
  332. text: "身体の大部分に焼けどを負う。",
  333. damage: "致命傷2/スタン"}],
  334. ]
  335. },
  336. "RF" => {
  337. name: "冷却",
  338. table: [
  339. [5,
  340. {name: "冷気",
  341. text: "軽い凍傷を受ける。",
  342. damage: "軽傷1"}],
  343. [10,
  344. {name: "霜の衣",
  345. text: "身体が薄い氷で覆われ、動きが鈍る。",
  346. damage: "軽傷1/疲労1"}],
  347. [13,
  348. {name: "凍傷",
  349. text: "凍傷により身体が傷つけられる。",
  350. damage: "軽傷3"}],
  351. [16,
  352. {name: "体温低下",
  353. text: "冷気によって体温を奪われる。",
  354. damage: "軽傷3/DOT:疲労1"}],
  355. [19,
  356. {name: "氷の枷",
  357. text: "肘や膝などが氷で覆われ、動きが取りにくくなる。",
  358. damage: "重傷1/マヒ"}],
  359. [22,
  360. {name: "大凍傷",
  361. text: "身体の各所に凍傷を受ける。",
  362. damage: "重傷1/DOT:疲労2"}],
  363. [25,
  364. {name: "氷の束縛",
  365. text: "下半身が凍りつき、動くことができない。",
  366. damage: "重傷2/マヒ"}],
  367. [28,
  368. {name: "視界不良",
  369. text: "頭部にも氷が張り、視界がふさがれる。",
  370. damage: "重傷2/スタン"}],
  371. [31,
  372. {name: "腕部凍結",
  373. text: "腕が凍りづけになり、動かすことができない。",
  374. damage: "重傷3/放心"}],
  375. [34,
  376. {name: "重度凍傷",
  377. text: "さらに体温が低下し、深刻な凍傷を受ける。",
  378. damage: "致命傷1"}],
  379. [37,
  380. {name: "全身凍結",
  381. text: "全身が凍りづけになる。",
  382. damage: "致命傷1/DOT:疲労2"}],
  383. [39,
  384. {name: "致命的凍傷",
  385. text: "身体全身に凍傷を受ける。",
  386. damage: "致命傷2"}],
  387. [9999,
  388. {name: "氷の棺",
  389. text: "完全に氷に閉じ込められる。",
  390. damage: "致命傷2/スタン、マヒ"}],
  391. ]
  392. },
  393. "EL" => {
  394. name: "電撃",
  395. table: [
  396. [5,
  397. {name: "静電気",
  398. text: "全身の毛が逆立つ。",
  399. damage: "疲労3"}],
  400. [10,
  401. {name: "電熱傷",
  402. text: "電流によって傷つく。",
  403. damage: "疲労1、軽傷1"}],
  404. [13,
  405. {name: "感電",
  406. text: "電流で傷つくと共に、身体が軽くしびれる。",
  407. damage: "疲労2、軽傷2"}],
  408. [16,
  409. {name: "閃光",
  410. text: "激しい電光により、一時的に視界がふさがれる。",
  411. damage: "軽傷3/スタン"}],
  412. [19,
  413. {name: "脚部感電",
  414. text: "電流により脚がしびれ、動けなくなる。",
  415. damage: "重傷1/マヒ"}],
  416. [22,
  417. {name: "大電熱傷",
  418. text: "身体の各所が電流によって傷つく。",
  419. damage: "疲労2、重傷2"}],
  420. [25,
  421. {name: "腕部負傷",
  422. text: "電流で腕がしびれ、動けなくなる。",
  423. damage: "軽傷1、重傷2/放心"}],
  424. [28,
  425. {name: "大感電",
  426. text: "電流によって身体中がしびれ、動けなくなる。",
  427. damage: "重傷2/スタン、マヒ"}],
  428. [31,
  429. {name: "一時心停止",
  430. text: "強力な電撃のショックにより、心臓がほんの一瞬だけ止まる。",
  431. damage: "疲労3、重傷3"}],
  432. [34,
  433. {name: "大電流",
  434. text: "全身に電流が駆け巡る。",
  435. damage: "重傷3/放心、マヒ"}],
  436. [37,
  437. {name: "致命電熱傷",
  438. text: "全身が電流によって傷つく。",
  439. damage: "重傷1、致命傷1"}],
  440. [39,
  441. {name: "心停止",
  442. text: "強力な電撃のショックにより、心臓が一時的に止まる。死の淵が見える。",
  443. damage: "疲労3、重傷1、致命傷1"}],
  444. [9999,
  445. {name: "組織炭化",
  446. text: "全身が電流で焼かれ、あちこちの組織が炭化する。",
  447. damage: "致命傷2/スタン"}],
  448. ]
  449. }
  450. }.freeze
  451. DAMAGE_TABLE_SE = {
  452. 1 "SL" => {
  453. name: "切断",
  454. table: [
  455. [5,
  456. {name: "軽い衝撃",
  457. text: "たいした傷ではないが、衝撃を受ける。",
  458. damage: "スタン"}],
  459. [10,
  460. {name: "小さな傷",
  461. text: "外装に傷がつく。",
  462. damage: "軽傷1"}],
  463. [13,
  464. {name: "大きな傷",
  465. text: "外装に大きな傷がつく。",
  466. damage: "軽傷2"}],
  467. [16,
  468. {name: "とても大きな傷",
  469. text: "外装にさらに大きな傷がつき、内部もダメージを受ける。",
  470. damage: "軽傷3/DOT:軽傷1"}],
  471. [19,
  472. {name: "外観破損",
  473. text: "外装の一部が欠ける。",
  474. damage: "軽傷4"}],
  475. [22,
  476. {name: "内部破損",
  477. text: "外装の一部が破損し、内部もダメージを受ける。",
  478. damage: "重傷1/DOT:軽傷1"}],
  479. [25,
  480. {name: "内部大破損",
  481. text: "内部の一部が大きく破損する。",
  482. damage: "重傷2"}],
  483. [28,
  484. {name: "一時不全",
  485. text: "外装の一部が壊れ、内部も大きなダメージを受ける。",
  486. damage: "重傷2/DOT:軽傷2"}],
  487. [31,
  488. {name: "裂傷",
  489. text: "傷をつけられ、内部が顔をのぞかせる。",
  490. damage: "重傷3"}],
  491. [34,
  492. {name: "視界不良",
  493. text: "取りつけられているカメラに不都合が生じる",
  494. damage: "重傷3/スタン"}],
  495. [37,
  496. {name: "大裂傷",
  497. text: "大きく切り裂かれ、内部が露わになる。",
  498. damage: "致命傷1"}],
  499. [39,
  500. {name: "機能不全",
  501. text: "重要な部品が壊れ、このままで機能に大きな障害が出る。",
  502. damage: "致命傷1/DOT:軽傷3"}],
  503. [9999,
  504. {name: "致命的損傷",
  505. text: "機能が停止しかねないほどの大きな損傷を受ける。",
  506. damage: "致命傷2"}],
  507. ]
  508. },
  509. "BL" => {
  510. name: "銃弾",
  511. table: [
  512. [5,
  513. {name: "軽い衝撃",
  514. text: "銃弾ははじいたが、衝撃を受ける。",
  515. damage: "スタン"}],
  516. [10,
  517. {name: "小さな銃創",
  518. text: "銃弾ははじいたが、外装に凹みができた。",
  519. damage: "軽傷2"}],
  520. [13,
  521. {name: "大きな銃創",
  522. text: "かろうじて銃弾ははじいたが、外装に大きな凹みができた。",
  523. damage: "軽傷3"}],
  524. [16,
  525. {name: "機能低下",
  526. text: "銃弾の衝撃で、内部の機能に不都合が講じた。",
  527. damage: "軽傷4/スロウ:-3"}],
  528. [19,
  529. {name: "とても大きな銃創",
  530. text: "銃弾をはじけず、外装に食い込んだ。",
  531. damage: "重傷1"}],
  532. [22,
  533. {name: "銃弾停止",
  534. text: "銃弾が貫通した。かろうじて内部にダメージはないようだ。",
  535. damage: "重傷2"}],
  536. [25,
  537. {name: "内部損傷",
  538. text: "銃弾が貫通した時、内部の機能に衝撃を受ける。",
  539. damage: "重傷2/放心"}],
  540. [28,
  541. {name: "内部破壊",
  542. text: "銃弾が貫通した時、内部にも大きなダメージを受ける。",
  543. damage: "重傷3"}],
  544. [31,
  545. {name: "内部大破壊",
  546. text: "銃弾が貫通した時、その衝撃で内部に一時的な損傷を受ける。",
  547. damage: "重傷3/スロウ:-5"}],
  548. [34,
  549. {name: "機能一部停止",
  550. text: "銃弾によって内部の機能が一時的に役に立たなくなっている。",
  551. damage: "致命傷1/スタン"}],
  552. [37,
  553. {name: "破損",
  554. text: "銃弾によって外装が吹き飛び、内部の一部が破壊される。",
  555. damage: "致命傷1/DOT:軽傷1"}],
  556. [39,
  557. {name: "大破損",
  558. text: "銃弾によって外装ごと内部の一部が吹き飛ぶ。",
  559. damage: "致命傷2"}],
  560. [9999,
  561. {name: "致命的な一撃",
  562. text: "銃弾が重要な部位に命中。衝撃で機能の大部分が一時的に停止する。",
  563. damage: "致命傷2/放心"}],
  564. ]
  565. },
  566. "IM" => {
  567. name: "衝撃",
  568. table: [
  569. [5,
  570. {name: "軽い衝撃",
  571. text: "傷も凹みもないが、衝撃を受ける。",
  572. damage: "スタン"}],
  573. [10,
  574. {name: "衝撃",
  575. text: "衝撃を受けて外装が凹む。",
  576. damage: "軽傷1"}],
  577. [13,
  578. {name: "大きな衝撃",
  579. text: "衝撃を受けて外装が大きく凹む。",
  580. damage: "軽傷2"}],
  581. [16,
  582. {name: "とても大きな衝撃",
  583. text: "衝撃を受けて外装が大きく凹み、機能が瞬間的に停止する。",
  584. damage: "軽傷2/放心"}],
  585. [19,
  586. {name: "内部圧迫",
  587. text: "外装が凹み、内部を圧迫している。",
  588. damage: "軽傷3/DOT:疲労3"}],
  589. [22,
  590. {name: "痛打",
  591. text: "当たり所が悪く、カメラ機能が一時的に停止する。",
  592. damage: "軽傷4/スタン"}],
  593. [25,
  594. {name: "内部衝撃",
  595. text: "当たり所が悪く、内部に大きなダメージを与える。機能が一時的に停止する。",
  596. damage: "軽傷5/放心"}],
  597. [28,
  598. {name: "機能障害",
  599. text: "衝撃によって機能の動作に障害が発生する。",
  600. damage: "重傷1/スロウ:-5"}],
  601. [31,
  602. {name: "外裝損傷",
  603. text: "外装が損傷し、その破片が内部に突き刺さる。",
  604. damage: "重傷1/放心、スタン"}],
  605. [34,
  606. {name: "外装大損傷",
  607. text: "外装が大きく損傷し、内部もいくつか破壊される。",
  608. damage: "重傷2/放心"}],
  609. [37,
  610. {name: "外装破壊",
  611. text: "外装の一部が吹き飛び、内部も破壊される。",
  612. damage: "重傷3/放心、スタン"}],
  613. [39,
  614. {name: "外装大破壊",
  615. text: "外装の一部が吹き飛び、内部も一緒に吹き飛ばされる。",
  616. damage: "致命傷1、疲労3"}],
  617. [9999,
  618. {name: "致命的破壊",
  619. text: "外装のほとんどが破壊され、内部もひしゃげ、潰される。",
  620. damage: "致命傷1/放心、スタン"}],
  621. ]
  622. },
  623. "BR" => {
  624. name: "灼熱",
  625. table: [
  626. [5,
  627. {name: "軽い溶解",
  628. text: "外装が少しだけ溶け、機能が低下する。",
  629. damage: "スタン"}],
  630. [10,
  631. {name: "溶解",
  632. text: "外装が溶ける。",
  633. damage: "軽傷1"}],
  634. [13,
  635. {name: "温度上昇",
  636. text: "熱によって、外装だけでなく内部も少しだけ溶解する。",
  637. damage: "軽傷2、疲労1"}],
  638. [16,
  639. {name: "温度大上昇",
  640. text: "熱によって、外装だけでなく内部が溶解する。",
  641. damage: "軽傷3/放心"}],
  642. [19,
  643. {name: "発火",
  644. text: "外装に火が燃え移る。",
  645. damage: "軽傷3/DOT:軽傷1"}],
  646. [22,
  647. {name: "爆発",
  648. text: "爆発により外装の一部が吹き飛ばされる。",
  649. damage: "重傷1/スタン"}],
  650. [25,
  651. {name: "痕が残るほどの大きく外装が溶解する。",
  652. text: "大溶解",
  653. damage: "重傷2"}],
  654. [28,
  655. {name: "熱波",
  656. text: "強力な熱により内部機能が低下する。",
  657. damage: "重傷2/スタン"}],
  658. [31,
  659. {name: "大爆発",
  660. text: "激しい爆発で外装が大きく吹き飛ばされ、内部にもダメージを受ける。",
  661. damage: "重傷3/放心"}],
  662. [34,
  663. {name: "大発火",
  664. text: "広範囲に火が燃え移る。",
  665. damage: "重傷3/DOT:軽傷1"}],
  666. [37,
  667. {name: "炭化",
  668. text: "高熱のあまり、焼けた部分が炭化してしまう。",
  669. damage: "致命傷1"}],
  670. [39,
  671. {name: "内部溶解",
  672. text: "内部に熱や炎が回り、大きく溶解する。",
  673. damage: "致命傷1/DOT:軽傷1"}],
  674. [9999,
  675. {name: "致命的溶解",
  676. text: "外装や内部の大部分が溶解する。",
  677. damage: "致命傷2"}],
  678. ]
  679. },
  680. "RF" => {
  681. name: "冷却",
  682. table: [
  683. [5,
  684. {name: "軽い冷却",
  685. text: "冷気で機能が低下する。",
  686. damage: "スタン"}],
  687. [10,
  688. {name: "冷気",
  689. text: "外装が薄い氷で覆われる。",
  690. damage: "軽傷1"}],
  691. [13,
  692. {name: "霜の衣",
  693. text: "外装が薄い氷で覆われ、動作が鈍る。",
  694. damage: "軽傷2/疲労1"}],
  695. [16,
  696. {name: "軽い凍結",
  697. text: "凍結によって外装の一部が痛む。",
  698. damage: "軽傷3"}],
  699. [19,
  700. {name: "温度低下",
  701. text: "冷気によって機能が低下する。",
  702. damage: "軽傷3/DOT:疲労1"}],
  703. [22,
  704. {name: "氷の枷",
  705. text: "可動部などが氷で覆われ、動きが取りにくくなる。",
  706. damage: "重傷1/スタン"}],
  707. [25,
  708. {name: "大凍結",
  709. text: "外装の大部分が凍結する。",
  710. damage: "重傷1/DOT:疲労2"}],
  711. [28,
  712. {name: "氷の束縛",
  713. text: "可動部などが完全に凍りつき、動くことができない。",
  714. damage: "重傷2/放心"}],
  715. [31,
  716. {name: "視界不良",
  717. text: "カメラのレンズにも氷が張り、視界がふさがれる。",
  718. damage: "重傷2/スタン"}],
  719. [34,
  720. {name: "動作不良",
  721. text: "凍結によって一部動作に不都合が生じている。",
  722. damage: "重傷3/放心"}],
  723. [37,
  724. {name: "重度凍結",
  725. text: "さらに温度が低下し、内部にも深刻なダメージを受ける。",
  726. damage: "致命傷1"}],
  727. [39,
  728. {name: " 全身凍結",
  729. text: "全体が凍りづけになる。",
  730. damage: "致命傷1/DOT:疲労2"}],
  731. [9999,
  732. {name: "致命的凍結",
  733. text: "外装だけでなく、内部も致命的なダメージを受ける。",
  734. damage: "致命傷2"}],
  735. ]
  736. },
  737. "EL" => {
  738. name: "電撃",
  739. table: [
  740. [5,
  741. {name: "軽い電撃",
  742. text: "電撃で機能が低下する。",
  743. damage: "スタン"}],
  744. [10,
  745. {name: "帯電",
  746. text: "帯電により軽いダメージを受ける。",
  747. damage: "疲労3"}],
  748. [13,
  749. {name: "電熱傷",
  750. text: "電流によって外装が傷つく。",
  751. damage: "疲労1、軽傷1"}],
  752. [16,
  753. {name: "軽い感電",
  754. text: "電流で傷つくと共に、内部に軽いダメージを受ける。",
  755. damage: "疲労2、軽傷2"}],
  756. [19,
  757. {name: "閃光",
  758. text: "激しい閃光により、一時的にカメラ機能がマヒする。",
  759. damage: "軽傷3/スタン"}],
  760. [22,
  761. {name: "感電",
  762. text: "電流により内部がダメージを受け、一時的に動作がマヒする。",
  763. damage: "重傷1/放心"}],
  764. [25,
  765. {name: "大電熱傷",
  766. text: "外装の各所が電流によって傷つく。",
  767. damage: "疲労2、重傷2"}],
  768. [28,
  769. {name: "感電による負傷",
  770. text: "外装だけでなく、内部も大きなダメージを受け、機能がマヒする。",
  771. damage: "軽傷1、重傷2/放心"}],
  772. [31,
  773. {name: "大感電",
  774. text: "電流によって機能のほとんどがマヒして、動作しなくなる。",
  775. damage: "重傷2/放心、スタン"}],
  776. [34,
  777. {name: "大電流",
  778. text: "強力な電撃のショックにより、内部にも多大なダメージを受ける。",
  779. damage: "疲労3、重傷3"}],
  780. [37,
  781. {name: "一時停止",
  782. text: "全身に電流が駆け巡り、機能の大部分が動作不良を起こす。",
  783. damage: "重傷3/放心、スタン"}],
  784. [39,
  785. {name: "致命電熱傷",
  786. text: "全体が電流によって傷つく。",
  787. damage: "重傷1、致命傷"}],
  788. [9999,
  789. {name: "機能停止",
  790. text: "強力な電撃のショックにより、故障寸前のダメージを受ける。",
  791. damage: "疲労3、重傷1、致命傷1"}],
  792. ]
  793. }
  794. }.freeze
  795. end
  796. end
  797. end

lib/bcdice/game_system/GehennaAn.rb

95.65% lines covered

76.92% branches covered

69 relevant lines. 66 lines covered and 3 lines missed.
26 total branches, 20 branches covered and 6 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class GehennaAn < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'GehennaAn'
  7. # ゲームシステム名
  8. 1 NAME = 'ゲヘナ・アナスタシス'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'けへなあなすたしす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. 戦闘判定と通常判定に対応。幸運の助け、連撃増加値(戦闘判定)、闘技チット(戦闘判定)を自動表示します。
  14. ・戦闘判定 (nGAt+m)
  15.  ダイス数n、目標値t、修正値mで戦闘判定を行います。
  16.  幸運の助け、連撃増加値、闘技チットを自動処理します。
  17. ・通常判定 (nGt+m)
  18.  ダイス数n、目標値t、修正値mで通常判定を行います。
  19.  幸運の助けを自動処理します。(連撃増加値、闘技チットを表示抑制します)
  20. INFO_MESSAGE_TEXT
  21. 1 register_prefix('\d+G\d+', '\d+GA\d+', '\d+R6')
  22. 1 def initialize(command)
  23. 19 super(command)
  24. 19 @sort_add_dice = true
  25. 19 @sort_barabara_dice = true
  26. end
  27. 1 private
  28. 1 def replace_text(string)
  29. 19 string
  30. 14 .gsub(/(\d+)GA(\d+)([+-][+\-\d]+)/) { "#{Regexp.last_match(1)}R6#{Regexp.last_match(3)}>=#{Regexp.last_match(2)}[1]" }
  31. 3 .gsub(/(\d+)GA(\d+)/) { "#{Regexp.last_match(1)}R6>=#{Regexp.last_match(2)}[1]" }
  32. .gsub(/(\d+)G(\d+)([+-][+\-\d]+)/) { "#{Regexp.last_match(1)}R6#{Regexp.last_match(3)}>=#{Regexp.last_match(2)}[0]" }
  33. 2 .gsub(/(\d+)G(\d+)/) { "#{Regexp.last_match(1)}R6>=#{Regexp.last_match(2)}[0]" }
  34. end
  35. 1 public
  36. 1 def eval_game_system_specific_command(string)
  37. 19 string = replace_text(string)
  38. 19 else: 19 then: 0 unless /(^|\s)S?((\d+)[rR]6([+\-\d]+)?([>=]+(\d+))(\[(\d)\]))(\s|$)/i =~ string
  39. return nil
  40. end
  41. 19 string = Regexp.last_match(2)
  42. 19 diceCount = Regexp.last_match(3).to_i
  43. 19 modText = Regexp.last_match(4)
  44. 19 diff = Regexp.last_match(6).to_i
  45. 19 mode = Regexp.last_match(8).to_i
  46. 19 mod = ArithmeticEvaluator.eval(modText)
  47. 19 diceArray = @randomizer.roll_barabara(diceCount, 6).sort
  48. 19 diceValue = diceArray.sum()
  49. 19 diceText = diceArray.join(",")
  50. 19 dice_1st = ""
  51. 19 isLuck = true
  52. 19 diceValue = 0
  53. # 幸運の助けチェック
  54. 19 diceArray.each do |i|
  55. 135 then: 116 if dice_1st != ""
  56. 116 then: 116 else: 0 if (dice_1st != i) || (i < diff)
  57. 116 isLuck = false
  58. end
  59. else: 19 else
  60. 19 dice_1st = i
  61. end
  62. 135 then: 51 else: 84 diceValue += 1 if i >= diff
  63. end
  64. 19 then: 0 else: 19 diceValue *= 2 if isLuck && (diceCount > 1)
  65. 19 output = "#{diceValue}[#{diceText}]"
  66. 19 success = diceValue + mod
  67. 19 then: 3 else: 16 success = 0 if success < 0
  68. 19 failed = diceCount - diceValue
  69. 19 then: 0 else: 19 failed = 0 if failed < 0
  70. 19 then: 8 if mod > 0
  71. 8 else: 11 output += "+#{mod}"
  72. 11 then: 6 else: 5 elsif mod < 0
  73. 6 output += mod.to_s
  74. end
  75. 19 then: 19 if /[^\d\[\]]+/ =~ output
  76. 19 output = "(#{string}) > #{output} > 成功#{success}、失敗#{failed}"
  77. else: 0 else
  78. output = "(#{string}) > #{output}"
  79. end
  80. # 連撃増加値と闘技チット
  81. 19 output += getAnastasisBonusText(mode, success)
  82. 19 return output
  83. end
  84. 1 private
  85. 1 def getAnastasisBonusText(mode, success)
  86. 19 then: 2 else: 17 return '' if mode == 0
  87. 17 ma_bonus = ((success - 1) / 2).to_i
  88. 17 then: 0 else: 17 ma_bonus = 7 if ma_bonus > 7
  89. 17 bonus_str = ''
  90. 17 then: 8 else: 9 bonus_str += "連撃[+#{ma_bonus}]/" if ma_bonus > 0
  91. 17 bonus_str += "闘技[#{getTougiBonus(success)}]"
  92. 17 return " > #{bonus_str}"
  93. end
  94. 1 def getTougiBonus(success)
  95. table = [
  96. 17 [6, '1'],
  97. [13, '2'],
  98. [18, '3'],
  99. [22, '4'],
  100. [99, '5'],
  101. ]
  102. 17 return get_table_by_number(success, table)
  103. end
  104. end
  105. end
  106. end

lib/bcdice/game_system/GeishaGirlwithKatana.rb

98.11% lines covered

93.75% branches covered

53 relevant lines. 52 lines covered and 1 lines missed.
16 total branches, 15 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class GeishaGirlwithKatana < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'GeishaGirlwithKatana'
  7. # ゲームシステム名
  8. 1 NAME = 'ゲイシャ・ガール・ウィズ・カタナ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'けいしやかあるういすかたな'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定 (GK#n)
  14. 役やチョムバを含めて1回分のダイスロールを判定します。
  15.  役は (通常判定)/(戦闘時) の順で両方出力されます。
  16. GK のみの場合5%の確率でチョムバます。
  17. GK#3 の様に #n をつけることによってチョムバの確率をn%にすることができます。
  18.  例)GK GK#10
  19. ・隠しコマンド (GL)
  20. 必ずチョムバします。GMが空気を読んでチョムバさせたいときや、
  21. GKコマンドを打ち間違えてチョムバするを想定してます。
  22.  例)GL
  23. MESSAGETEXT
  24. 1 register_prefix('GK', 'GL')
  25. 1 def eval_game_system_specific_command(command)
  26. 22 output = nil
  27. 22 then: 1 else: 21 if /^GL$/i =~ command
  28. 1 return getChombaResultText()
  29. end
  30. 21 else: 21 then: 0 unless /^GK(#(\d+))?$/i =~ command
  31. return output
  32. end
  33. 21 chomba_counter = Regexp.last_match(2)
  34. 21 then: 2 else: 19 if isChomba(chomba_counter)
  35. 2 return getChombaResultText()
  36. end
  37. 19 diceList = @randomizer.roll_barabara(3, 6).sort
  38. 19 yakuResult = getYaku(diceList)
  39. 19 else: 11 then: 8 unless yakuResult.nil?
  40. 8 return getResultTextByDice(diceList, "【役】#{yakuResult}")
  41. end
  42. 11 deme, zorome = getDemeZorome(diceList)
  43. 11 then: 2 else: 9 if deme == 0
  44. 2 return getResultTextByDice(diceList, "失敗")
  45. end
  46. 9 then: 3 else: 6 yp = (zorome == 1 ? " YPが1増加" : "")
  47. 9 output = getResultTextByDice(diceList, "達成値#{deme}#{yp}")
  48. 9 debug("getGGwKResult(command) result", output)
  49. 9 return output
  50. end
  51. 1 def isChomba(chomba_counter)
  52. 21 chomba_counter ||= 5
  53. 21 chomba_counter = chomba_counter.to_i
  54. 21 chomba = @randomizer.roll_once(100)
  55. 21 return (chomba <= chomba_counter)
  56. end
  57. 1 def getChombaResultText()
  58. 3 getResultText("チョムバ!!")
  59. end
  60. 1 def getYaku(diceList)
  61. rule = {
  62. 19 [1, 2, 3] => "自動失敗/自分の装甲効果無しでダメージを受けてしまう",
  63. [4, 5, 6] => "自動成功/敵の装甲を無視してダメージを与える",
  64. [1, 1, 1] => "10倍成功 YPが10増加/10倍ダメージ YPが10増加",
  65. [2, 2, 2] => "2倍成功/2倍ダメージ",
  66. [3, 3, 3] => "3倍成功/3倍ダメージ",
  67. [4, 4, 4] => "4倍成功/4倍ダメージ",
  68. [5, 5, 5] => "5倍成功/5倍ダメージ",
  69. [6, 6, 6] => "6倍成功/6倍ダメージ",
  70. }
  71. 19 yaku = rule[diceList]
  72. 19 return yaku
  73. end
  74. 1 def getDemeZorome(diceList)
  75. 11 deme = 0
  76. 11 zorome = 0
  77. 11 then: 5 if diceList[0] == diceList[1]
  78. 5 deme = diceList[2]
  79. 5 else: 6 zorome = diceList[0]
  80. 6 then: 4 else: 2 elsif diceList[1] == diceList[2]
  81. 4 deme = diceList[0]
  82. 4 zorome = diceList[1]
  83. end
  84. 11 return deme, zorome
  85. end
  86. 1 def getResultTextByDice(diceList, result)
  87. 19 getResultText("#{diceList.join(',')} > #{result}")
  88. end
  89. 1 def getResultText(result)
  90. 22 "(3B6) > #{result}"
  91. end
  92. end
  93. end
  94. end

lib/bcdice/game_system/GhostLive.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class GhostLive < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'GhostLive'
  7. # ゲームシステム名
  8. 1 NAME = '実況ゴーストライヴ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'しつきようこおすとらいふ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGE
  13. ■追加目標表(p11)
  14. ATT, AdditionalTargetTable
  15. ■種別:地縛霊(p26)
  16. □A.霊障リスト
  17. JHA, JibakuHauntA
  18. □B.霊障効果リスト
  19. JHB, JibakuHauntB
  20. ■種別:シャイな幽霊(p27)
  21. □A.霊障リスト
  22. SHA, ShyHauntA
  23. □B.霊障効果リスト
  24. SHB, ShyHauntB
  25. ■種別:ぐちゃぐちゃ(p28)
  26. □A.霊障リスト
  27. GHA, GuchaHauntA
  28. □B.霊障効果リスト
  29. GHB, GuchaHauntB
  30. MESSAGE
  31. 1 def eval_game_system_specific_command(command)
  32. 14 command = ALIAS[command] || command
  33. 14 roll_tables(command, TABLES)
  34. end
  35. TABLES = {
  36. 1 "AdditionalTargetTable" => DiceTable::Table.new(
  37. "追加目標表",
  38. "1D6",
  39. [
  40. "オバケを撮影する。(依頼主:専門家/報酬:1L)",
  41. "誰かひとりが霊障を[サイクル数]回受ける。(依頼主:専門家/報酬:[サイクル数]L)",
  42. "誰かひとりが[精神力]を10以下の状態で帰る。(依頼主:専門家/報酬:3L)",
  43. "[精神力]の平均が20以下の状態で帰る。(依頼主:リスナー/報酬:[視聴回数]を10倍)",
  44. "全員がスマホ以外の[アイテム]を1個だけ持ち込んで生還する。(依頼主:リスナー/報酬:[視聴回数]を10倍)",
  45. "すべての[回収品]を集める。(依頼主:専門家/報酬:5L)",
  46. ]
  47. ),
  48. "JibakuHauntA" => DiceTable::Table.new(
  49. "地縛霊:霊障リスト",
  50. "1D6",
  51. [
  52. "隙間――家具の隙間、扉の隙間、そんな暗がりから視線を感じる。",
  53. "腐臭――吐き気を催すような、下水に似た臭いが漂ってくる。",
  54. "吐息――「ハァ……」耳元に、やけに湿った吐息が吹きかけられる。",
  55. "足音――立ち止まる度に、ひとつ多く足音が響く。誰か、いる……?",
  56. "背後――振り向いても、そこには誰もいない。それなのに、ずっと後ろに気配を感じる。",
  57. "鏡――鏡に背を向けた瞬間、あり得ない強さでそちらへ引き寄せられた。肩には手の形のアザができている。",
  58. ]
  59. ),
  60. "JibakuHauntB" => DiceTable::Table.new(
  61. "地縛霊:霊障効果リスト",
  62. "1D6",
  63. [
  64. "[精神力]減少:[1D2+PC人数]点/[視聴回数]増加:とくになし/特殊効果:とくになし",
  65. "[精神力]減少:[1D4+PC人数]点/[視聴回数]増加:とくになし/特殊効果:とくになし",
  66. "[精神力]減少:[1D6+PC人数]点/[視聴回数]増加:2倍/特殊効果:とくになし",
  67. "[精神力]減少:[1D10+PC人数]点/[視聴回数]増加:3倍/特殊効果:シーンに登場しているPCの[アイテム]を1つ破壊する。",
  68. "[精神力]減少:[1D20+PC人数]点/[視聴回数]増加:5倍/特殊効果:シーンに登場しているPCのスマホを破壊する。",
  69. "[精神力]減少:[1D100+PC人数]点/[視聴回数]増加:10倍/特殊効果:シーンに登場しているPCのスマホを破壊する。",
  70. ]
  71. ),
  72. "ShyHauntA" => DiceTable::Table.new(
  73. "シャイな幽霊:霊障リスト",
  74. "1D6",
  75. [
  76. "倦怠感――歩くのも辛いくらいの倦怠感。生きているのも辛い。",
  77. "ラップ音――弾けるような、叩くような音が連続して聞こえる。",
  78. "空飛ぶ皿――棚に収まっていた食器が、不意に飛び出し、けたたましい音を立てて砕けていく。",
  79. "頭痛――頭が、割れそうに痛い。小さな物音ですら頭に響いてくる。",
  80. "点滅――灯りが明滅する。……あれ、ここ電気通ってたっけ?",
  81. "血文字――壁に、床に、赤⿊い液体が滲み出す。それは文字を形作った。「か え れ」",
  82. ]
  83. ),
  84. "ShyHauntB" => DiceTable::Table.new(
  85. "シャイな幽霊:霊障効果リスト",
  86. "1D6",
  87. [
  88. "[精神力]減少:[2+PC人数]点/[視聴回数]増加:とくになし/特殊効果:とくになし",
  89. "[精神力]減少:[4+PC人数]点/[視聴回数]増加:2倍/特殊効果:シーンに登場しているPCがふたりの場合、追加で[精神力]を2減少させる。",
  90. "[精神力]減少:[6+PC人数]点/[視聴回数]増加:3倍/特殊効果:シーンに登場しているPCがひとりの場合、追加で[精神力]を4減少させる。",
  91. "[精神力]減少:[10+PC人数]点/[視聴回数]増加:5倍/特殊効果:シーンに登場しているPCがふたりの場合、追加で[精神力]を6減少させる。",
  92. "[精神力]減少:[20+PC人数]点/[視聴回数]増加:10倍/特殊効果:シーンに登場しているPCがひとりの場合、追加で[精神力]を2減少させる。",
  93. "[精神力]減少:[40+PC人数]点/[視聴回数]増加:20倍/特殊効果:シーンに登場しているPCのスマホを破壊する。",
  94. ]
  95. ),
  96. "GuchaHauntA" => DiceTable::Table.new(
  97. "ぐちゃぐちゃ:霊障リスト",
  98. "1D6",
  99. [
  100. "走る人形――ひび割れた人形が落ちている。一瞬視線をそらした瞬間、それはありえない動きで走り去っていった。",
  101. "血痕――天井から血が滴ってくる。その量は、おおよそ人一人分……いや、それ以上だ。",
  102. "着信――スマホの着信音が鳴る。こんな時に誰が――表示されていたのは、死んだはずの知り合いの名前だった。",
  103. "自分に似た他人――自分にそっくりな人が目の前に立っていた、気がする。",
  104. "衝撃――誰かに思いっきり押された気がしたのに誰もいない。",
  105. "記憶がない――数分間のことを何も覚えてない。コメント欄がリスナーの心配する声でいっぱいだ。いったい何が……?",
  106. ]
  107. ),
  108. "GuchaHauntB" => DiceTable::Table.new(
  109. "ぐちゃぐちゃ:霊障効果リスト",
  110. "1D6",
  111. [
  112. "[精神力]減少:[5+PC人数]点/[視聴回数]増加:2倍/特殊効果:とくになし",
  113. "[精神力]減少:[10+PC人数]点/[視聴回数]増加:3倍/特殊効果:とくになし",
  114. "[精神力]減少:[2D10+PC人数]点/[視聴回数]増加:4倍/特殊効果:シーンに登場しているPCがふたりの場合、追加で[精神力]を5減少させる。",
  115. "[精神力]減少:[3D10+PC人数]点/[視聴回数]増加:5倍/特殊効果:シーンに登場しているPCがひとりの場合、[アイテム]をランダムに1つ壊す。",
  116. "[精神力]減少:[1D100+PC人数]点/[視聴回数]増加:10倍/特殊効果:シーンに登場しているPCのスマホを破壊する。",
  117. "[精神力]減少:[1D100+10+PC人数]点/[視聴回数]増加:20倍/特殊効果:すべてのPCのスマホを破壊する。",
  118. ]
  119. ),
  120. }.transform_keys(&:upcase).freeze
  121. 1 ALIAS = {
  122. "ATT" => "AdditionalTargetTable",
  123. "JHA" => "JibakuHauntA",
  124. "JHB" => "JibakuHauntB",
  125. "SHA" => "ShyHauntA",
  126. "SHB" => "ShyHauntB",
  127. "GHA" => "GuchaHauntA",
  128. "GHB" => "GuchaHauntB",
  129. }.transform_values(&:upcase).freeze
  130. 1 register_prefix(TABLES.keys, ALIAS.keys)
  131. end
  132. end
  133. end

lib/bcdice/game_system/GoblinSlayer.rb

96.67% lines covered

93.48% branches covered

90 relevant lines. 87 lines covered and 3 lines missed.
46 total branches, 43 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class GoblinSlayer < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'GoblinSlayer'
  7. # ゲームシステム名
  8. 1 NAME = 'ゴブリンスレイヤーTRPG'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'こふりんすれいやあTRPG'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定 GS(x)@c#f>=y
  14.  2d6の判定を行い、達成値を出力します。
  15.  xは基準値、yは目標値、cは大成功の下限、fは大失敗の上限です。いずれも省略可能です。
  16.  cが未指定の場合には c=12 、fが未指定の場合には f=2 となります。
  17.  yが設定されている場合、大成功/成功/失敗/大失敗を自動判定します。
  18.  例)GS>=12 GS>10 GS(10)>14 GS+10>=15 GS10>=15 GS(10) GS+10 GS10 GS
  19.    GS@10 GS@10#3 GS#3@10
  20. ・祈念 MCPI(n)$m
  21.  祈念を行います。
  22.  nは【幸運】などによるボーナスです。この値は省略可能です。
  23.  mは因果点の現在値です。
  24.  因果点の現在値を使用して祈念を行い、成功/失敗を自動判定します。
  25.  例)MCPI$3 MCPI(1)$4 MCPI+2$5 MCPI2$6
  26. ・命中判定の効力値によるボーナス DB(n)
  27.  ダメージ効力表による威力へのボーナスを自動で求めます。
  28.  nは命中判定の効力値です。
  29.  例)DB(15) DB12
  30. ※上記コマンドの計算内で割り算を行った場合、小数点以下は切り上げされます。
  31.  ただしダイス出目を割り算した場合、小数点以下は切り捨てされます。
  32.  例)入力:GS(8+3/2) 実行結果:(GS10) > 10 + 3[1,2] > 13
  33.    入力:2d6/2  実行結果:(2D6/2) > 3[1,2]/2 > 1
  34. ※MCPIでは、シークレットダイスを使用できません。
  35. MESSAGETEXT
  36. # 因果点は共有リソースなのでMCPIはシークレットダイスを無効化
  37. 1 register_prefix('GS', '^MCPI.*$', 'DB')
  38. 1 def initialize(command)
  39. 60 super(command)
  40. 60 @round_type = RoundType::CEIL
  41. end
  42. 1 def eval_game_system_specific_command(command)
  43. 59 case command
  44. when: 34 when /^GS/i
  45. 34 return getCheckResult(command)
  46. when: 14 when /^MCPI/i
  47. 14 return murmurChantPrayInvoke(command)
  48. when: 11 when /^DB/i
  49. 11 return damageBonus(command)
  50. else: 0 else
  51. return nil
  52. end
  53. end
  54. 1 def getCheckResult(command)
  55. 34 m = /^GS([-+]?\d+)?(?:(?:([@#])([-+]?\d+))(?:([@#])([-+]?\d+))?)?(?:(>=?)(\d+))?$/i.match(command)
  56. 34 else: 32 then: 2 unless m
  57. 2 return nil
  58. end
  59. 32 basis = m[1].to_i # 基準値
  60. 32 target = m[7].to_i
  61. 32 cmp_op = m[6]
  62. 32 without_compare = cmp_op.nil?
  63. 32 option1 = m[2]
  64. 32 option1_value = m[3]
  65. 32 option2 = m[4]
  66. 32 option2_param = m[5]
  67. 32 then: 0 else: 32 if option1 && option1 == option2
  68. return nil
  69. end
  70. 32 threshold_critical, threshold_fumble = calc_threshold(option1, option1_value, option2, option2_param)
  71. 32 dice_list = @randomizer.roll_barabara(2, 6)
  72. 32 total = dice_list.sum()
  73. 32 diceText = dice_list.join(",")
  74. 32 achievement = basis + total # 達成値
  75. 32 fumble = total <= threshold_fumble
  76. 32 critical = total >= threshold_critical
  77. 32 result = " > #{resultStr(achievement, target, cmp_op, fumble, critical)}"
  78. 32 then: 5 else: 27 if without_compare && !fumble && !critical
  79. 5 result = ""
  80. end
  81. 32 then: 19 else: 13 basis_str = basis == 0 ? "" : "#{basis} + "
  82. 32 return "(#{command}) > #{basis_str}#{total}[#{diceText}] > #{achievement}#{result}"
  83. end
  84. 1 CRITICAL = 12
  85. 1 FUMBLE = 2
  86. 1 def calc_threshold(option1, option1_value, _option2, option2_value)
  87. 32 then: 7 else: 25 critical, fumble = option1 == "@" ? [option1_value, option2_value] : [option2_value, option1_value]
  88. 32 then: 8 else: 24 then: 6 else: 26 return [critical&.to_i || CRITICAL, fumble&.to_i || FUMBLE]
  89. end
  90. 1 def murmurChantPrayInvoke(command)
  91. 14 m = /^MCPI(\+?\d+)?\$(\d+)$/i.match(command)
  92. 14 else: 13 then: 1 unless m
  93. 1 return nil
  94. end
  95. 13 luck = m[1].to_i # 幸運
  96. 13 volition = m[2].to_i # 因果点
  97. 13 then: 3 else: 10 if volition >= 12
  98. 3 return "因果点が12点以上の場合、因果点は使用できません。"
  99. end
  100. 10 dice_list = @randomizer.roll_barabara(2, 6)
  101. 10 total = dice_list.sum()
  102. 10 diceText = dice_list.join(",")
  103. 10 achievement = total + luck
  104. 10 result = " > #{resultStr(achievement, volition, '>=', false, false)}"
  105. 10 then: 4 else: 6 luck_str = luck == 0 ? "" : "+#{luck}"
  106. 10 return "祈念(2d6#{luck_str}) > #{total}[#{diceText}]#{luck_str} > #{achievement}#{result}, 因果点:#{volition}点 → #{volition + 1}点"
  107. end
  108. 1 def damageBonus(command)
  109. 11 m = /^DB(\d+)$/i.match(command)
  110. 11 else: 11 then: 0 unless m
  111. return nil
  112. end
  113. 11 num = m[1].to_i
  114. 11 fmt = "命中判定の効力値によるボーナス > "
  115. 11 then: 1 else: 10 if num < 15
  116. 1 return fmt + "なし"
  117. end
  118. times =
  119. 10 then: 2 if num >= 40
  120. 2 else: 8 5
  121. 8 then: 2 elsif num >= 30
  122. 2 else: 6 4
  123. 6 then: 2 elsif num >= 25
  124. 2 else: 4 3
  125. 4 then: 2 elsif num >= 20
  126. 2 2
  127. else: 2 else
  128. 2 1
  129. end
  130. 10 dice_list = @randomizer.roll_barabara(times, 6)
  131. 10 total = dice_list.sum()
  132. 10 diceText = dice_list.join(",")
  133. 10 return fmt + "#{total}[#{diceText}] > #{total}"
  134. end
  135. # 判定結果の文字列を返す
  136. # @param [Integer] achievement 達成値
  137. # @param [Integer] target 目標値
  138. # @param [String] cmp_op 達成値と目標値を比較する比較演算子
  139. # @param [Boolean] fumble ファンブルかどうか
  140. # @param [Boolean] critical クリティカルかどうか
  141. # @return [String]
  142. 1 def resultStr(achievement, target, cmp_op, fumble, critical)
  143. 42 then: 8 else: 34 return '大失敗' if fumble
  144. 34 then: 8 else: 26 return '大成功' if critical
  145. 26 then: 15 if cmp_op == ">="
  146. 15 then: 9 else: 6 return achievement >= target ? "成功" : "失敗"
  147. else: 11 else
  148. 11 then: 9 else: 2 return achievement > target ? "成功" : "失敗"
  149. end
  150. end
  151. end
  152. end
  153. end

lib/bcdice/game_system/GoldenSkyStories.rb

90.91% lines covered

50.0% branches covered

33 relevant lines. 30 lines covered and 3 lines missed.
12 total branches, 6 branches covered and 6 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class GoldenSkyStories < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'GoldenSkyStories'
  7. # ゲームシステム名
  8. 1 NAME = 'ゆうやけこやけ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ゆうやけこやけ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ※「ゆうやけこやけ」はダイスロールを使用しないシステムです。
  14. ※このダイスボットは部屋のシステム名表示用となります。
  15. ・下駄占い (GETA)
  16. あーしたてんきになーれ
  17. MESSAGETEXT
  18. 1 register_prefix('geta')
  19. 1 def initialize(command)
  20. 6 super(command)
  21. 6 @enabled_upcase_input = false
  22. end
  23. 1 def eval_game_system_specific_command(command)
  24. 4 debug('eval_game_system_specific_command command', command)
  25. 4 result = ''
  26. 4 else: 0 case command
  27. when: 4 when /geta/i
  28. 4 result = getaRoll()
  29. end
  30. 4 then: 0 else: 4 return nil if result.empty?
  31. 4 return "#{command} > #{result}"
  32. end
  33. 1 def getaRoll()
  34. 4 result = ""
  35. 4 dice = @randomizer.roll_once(7)
  36. # result << " あーしたてんきになーれっ > [#{diceList.join(',')}] > "
  37. 4 result += "下駄占い > "
  38. 4 getaString = ''
  39. 4 else: 0 case dice
  40. when: 1 when 1
  41. 1 getaString = '裏:あめ'
  42. when: 0 when 2
  43. getaString = '表:はれ'
  44. when: 1 when 3
  45. 1 getaString = '裏:あめ'
  46. when: 0 when 4
  47. getaString = '表:はれ'
  48. when: 0 when 5
  49. getaString = '裏:あめ'
  50. when: 1 when 6
  51. 1 getaString = '表:はれ'
  52. when: 1 when 7
  53. 1 getaString = '横:くもり'
  54. end
  55. 4 result += getaString
  56. 4 return result
  57. end
  58. end
  59. end
  60. end

lib/bcdice/game_system/Gorilla.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Gorilla < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Gorilla'
  7. # ゲームシステム名
  8. 1 NAME = 'ゴリラTRPG'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'こりらTRPG'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. 2D6ロール時のゴリティカル自動判定を行います。
  14. G = 2D6のショートカット
  15. 例) G>=7 : 2D6して7以上なら成功
  16. MESSAGETEXT
  17. 1 register_prefix('G')
  18. 1 def change_text(string)
  19. 48 string = string.gsub(/^(S)?G/i) { "#{Regexp.last_match(1)}2D6" }
  20. 30 return string
  21. end
  22. 1 def result_2d6(_total, _dice_total, dice_list, _cmp_op, _target)
  23. 13 then: 4 else: 9 if dice_list == [5, 5]
  24. 4 Result.critical("ゴリティカル(自動的成功)")
  25. end
  26. end
  27. end
  28. end
  29. end

lib/bcdice/game_system/GranCrest.rb

100.0% lines covered

90.0% branches covered

35 relevant lines. 35 lines covered and 0 lines missed.
10 total branches, 9 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class GranCrest < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'GranCrest'
  7. # ゲームシステム名
  8. 1 NAME = 'グランクレストRPG'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'くらんくれすとRPG'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・2D6の目標値判定でクリティカル処理
  14.  例)3d6>=19 3d6+5>=24
  15. ・邂逅表(MT)
  16. ・感情表(-FT)
  17.  ポジティブ感情表(PFT)、ネガティブ感情表(NFT)
  18. ・国特徴表(-CT)
  19.  カテゴリー表(CT)、地形表(TCT)、産業表(ICT)、人物表(PCT)
  20.  組織表(OCT)、拠点表(BCT)、文化表(CCT)
  21. MESSAGETEXT
  22. 1 def initialize(command)
  23. 32 super(command)
  24. 32 @sort_add_dice = true
  25. 32 @d66_sort_type = D66SortType::NO_SORT
  26. 32 @round_type = RoundType::FLOOR
  27. end
  28. # ゲーム別成功度判定(nD6)
  29. 1 def result_nd6(total, _dice_total, dice_list, cmp_op, target)
  30. 9 else: 9 then: 0 return nil unless cmp_op == :>=
  31. 9 result = Result.new
  32. 9 sequence = []
  33. 9 then: 6 else: 3 if dice_list.count(6) >= 2
  34. 6 total += 10
  35. 6 result.critical = true
  36. 6 sequence.push("(クリティカル)", total.to_s)
  37. end
  38. 9 then: 6 else: 3 if target != '?'
  39. 6 then: 3 if total >= target
  40. 3 sequence.push("成功")
  41. 3 result.success = true
  42. else: 3 else
  43. 3 sequence.push("失敗")
  44. 3 result.failure = true
  45. end
  46. end
  47. 9 then: 1 else: 8 if sequence.empty?
  48. 1 return nil
  49. end
  50. 8 result.text = sequence.join(" > ")
  51. 8 return result
  52. end
  53. 1 def eval_game_system_specific_command(command)
  54. 23 roll_tables(ALIASES[command] || command, TABLES)
  55. end
  56. TABLES = {
  57. 1 "MT" => DiceTable::D66OneThirdTable.new(
  58. "邂逅表",
  59. [
  60. "師匠\nあなたは彼(彼女)から多くのものを学んだ。あなたにとって、彼(彼女)は師であった。",
  61. "保護者\nあなたは彼(彼女)を兄や姉、あるいは父親のように慕っている。もちろん本当に血縁関係があってもよい。",
  62. "恩人\nあなたは彼(彼女)に恩義があり、その恩を返したいと思っている。",
  63. "忠誠\nあなたは彼(彼女)に忠誠を誓っている。それはあなたが望んでそうしているのか、別の事情があるのかは好きに設定すること。",
  64. "借り\nあなたは彼(彼女)に何らかの借りがある。その借りは必ず返さねばならないものだ。",
  65. "興味\nあなたは彼(彼女)に興味がある。善悪の問題ではない。どこかで、彼(彼女)を面白いと感じるのだ。",
  66. ],
  67. [
  68. "家族\nあなたは彼(彼女)は家族同然の関係だ。もちろん本当に血縁関係があってもよい。",
  69. "友人\nあなたと彼(彼女)は友人だ。共に時間を過ごし、その友情を育んできた。",
  70. "仲間\nあなたと彼(彼女)は仲間同士だ。同じ目的、同じ志を持ち、共に協力してこれまで事に当たってきた。",
  71. "仕事\nあなたと彼(彼女)は仕事上でのつきあいだ。仕事相手として信頼できる相手ではあるが、それ以上でもそれ以下でもない。",
  72. "腐れ縁\nあなたと彼(彼女)は、何かにつけてよく顔を合わせる腐れ縁だ。長いつきあいと言えるだろう。",
  73. "忘却\nあなたと彼(彼女)は、どこかで出会ったことがある。だが、それがいつ、どこだったかを思い出すことはできない。",
  74. ],
  75. [
  76. "慕情\nあなたは彼(彼女)を慕っている。心の底から、純粋に、それは恋愛感情と呼べるものかもしれない。",
  77. "貸し\nあなたは彼(彼女)に貸しがある。いつか、この貸しは必ず返してもらわねばならない。",
  78. "弟妹\nあなたは彼(彼女)を弟や妹のように思っている。もちろん本当に血縁関係があってもよい。",
  79. "秘密\nあなたと彼(彼女)は秘密を共有している仲だ。一方的に秘密を握られているのかもしれない。",
  80. "好敵手\nあなたと彼(彼女)は好敵手――ライバルという関係がふさわしい。いつかヤツに勝つため、あなたは研鑽を積む。",
  81. "仇敵\n彼(彼女)はあなたの仇敵だ。いつかヤツを殺し、雪辱を果たさなければ気が済まない。",
  82. ]
  83. ),
  84. "PFT" => DiceTable::D66OneThirdTable.new(
  85. "ポジティブ感情表",
  86. [
  87. "好奇心\nあなたは彼(彼女)に好奇心を感じた。彼(彼女)はとても面白い。もっと知ってみたいと感じた。",
  88. "憧憬\nあなたは彼(彼女)にあこがれを感じた。彼(彼女)のようになりたいと思った。その思いは今でも続いている。",
  89. "尊敬\nあなたは彼(彼女)を尊敬している。彼(彼女)を敬い、決して下には見ないだろう。",
  90. "同志\nあなたは彼(彼女)と同じ志を持つものだと感じている。共に道を行く仲間、もしかしたら好敵手なのかもしれない。",
  91. "友情\nあなたは彼(彼女)に友情を感じている。彼(彼女)は得がたい友人だ。あなたを助け、そしてあなたも向こうを助けることだろう。",
  92. "慕情\nあなたは彼(彼女)にほのかな愛情を感じている。それは恋と呼ばれるものかもしれないし、違うかもしれない。",
  93. ],
  94. [
  95. "庇護\nあなたは彼(彼女)を守ってやらねばならぬ、と感じている。あなたが彼(彼女)を苦難から救うのだ。",
  96. "幸福感\nあなたは彼(彼女)を見ると、幸福感に包まれる。彼(彼女)がそばにいる、それがあなたにとっては幸せなのだ。",
  97. "信頼\nあなたは彼(彼女)を信用している。その能力を、もしくは性格を、信じ、頼っている。",
  98. "尽力\nあなたは彼(彼女)に力を尽くしたいと考えている。彼(彼女)の役に立つ、それがあなたのしたいことだ。",
  99. "可能性\nあなたは彼(彼女)に、何らかの可能性を感じている。今はまだ未熟でも、彼(彼女)はいつか花開くだろう。",
  100. "慈愛\nあなたは彼(彼女)に愛情を感じている。見返りなどなくとも、あなたは彼(彼女)の力となるだろう。",
  101. ],
  102. [
  103. "かわいい\nあなたは彼(彼女)をかわいいと思っている。いつまでも愛でることができたら、それはどんなに幸せだろうか。",
  104. "同情\nあなたは彼(彼女)に同情している。その過去か、それとも別のものか、あなたは彼(彼女)をかわいそうだと思っている。",
  105. "連帯感\nあなたは彼(彼女)に連帯感を持っている。彼(彼女)はどこかで自分と似ていると思っている。",
  106. "親近感\nあなたは彼(彼女)に親近感を抱いている。彼(彼女)は家族のようなものだ。そう接してもよいだろう。",
  107. "感服\nあなたは彼(彼女)に感服している。その能力か、それとも別の事柄か、彼(彼女)をすごいと感じ、認めている。",
  108. "誠意\nあなたは彼(彼女)に誠意を感じている。他がどうであろうとも、彼(彼女)はあなたにとってみれば誠実だ。",
  109. ]
  110. ),
  111. "NFT" => DiceTable::D66OneThirdTable.new(
  112. "ネガティブ感情表",
  113. [
  114. "憤憑\nあなたは彼(彼女)に憤憑を覚えている。性格か、その癖か、何かにあなたは怒りを覚えているのだ。",
  115. "悲哀\nあなたは彼(彼女)に悲哀を感じている。その過去か、それとも別のものか、あなたは彼(彼女)をかわいそうだと感じている。",
  116. "寂しさ\nあなたは彼(彼女)を見ると寂しさを覚える。もっと距離を近づけたいのか、別の理由なのか、ともあれ、どこか寂しいのだ。",
  117. "食傷\nあなたは彼(彼女)に食傷を覚えている。口癖や考え方、あるいは別のものにうんざりしているのだ。",
  118. "敵愾心\nあなたは彼(彼女)に敵愾心を覚えている。ここだけは彼(彼女)に負けたくないと思っているのだ。",
  119. "不快感\nあなたは彼(彼女)に不快感を覚えている。他のところはともかく、どうしてもここだけはイヤだ、という部分があるのだ。",
  120. ],
  121. [
  122. "猜疑心\nあなたは彼(彼女)に猜疑心を覚えている。なぜか、彼(彼女)のことを信じられない。どこかで疑ってしまうのだ。",
  123. "嫌悪\nあなたは彼(彼女)のことを嫌っている。考え方なのか、癖なのか、どうしても拒否感を覚えずにはいられない。",
  124. "隔意\nあなたは彼(彼女)とは隔たりがあると感じている。何かの分野について、向こうと自分には距離があると思っている。",
  125. "憎悪\nあなたは彼(彼女)を憎んでいる。ここだけは許せない、という部分について、憎しみを燃やさずにはいられない。",
  126. "偏愛\nあなたは彼(彼女)を愛している。だが、その愛はどこか偏りがある、一方通行気味のものだ。",
  127. "疎外感\nあなたは彼(彼女)に疎外感を覚えている。なぜか仲間はずれにされているような、そんな感覚がまとわりつく。",
  128. ],
  129. [
  130. "劣等感\nあなたは彼(彼女)に劣等感を覚えている。彼(彼女)には敵わない、なぜか上に行かれる、そんなコンプレックスを持っている。",
  131. "不安\nあなたは彼(彼女)を見ると、どこか不安を覚える。理由は無いのかもしれない、なぜかイヤな予感を覚えるのだ。",
  132. "恐怖\nあなたは彼(彼女)を怖がっている。その能力や考え方、あるいは彼(彼女)自身ではなく、失うことを恐れているのかもしれない。",
  133. "嫉妬\nあなたは彼(彼女)に嫉妬している。その過去や能力、あるいは環境を羨ましいと思わずにはいられない。",
  134. "驚異\nあなたは彼(彼女)に脅威を感じている。自分にとって致命的な存在になるかもしれないと考えている。",
  135. "侮蔑\nあなたは彼(彼女)を侮り、蔑んでいる。彼(彼女)は自分より下の存在であると思っている。",
  136. ]
  137. ),
  138. "CT" => DiceTable::Table.new(
  139. "国特徴・カテゴリー表",
  140. "1D6",
  141. [
  142. "地形(TCT)\n森林、山岳、河川など、その国に存在する地勢を表す。",
  143. "産業(ICT)\n農耕が盛ん、鍛冶技術に優れるなど、その国の産業を表す。",
  144. "人物(PCT)\n腕のよい鍛冶屋がいる、知識豊富な薬師がいるなど、その国にいる人物を表す。",
  145. "組織(OCT)\n狩人の組合がある、キャラバンがいるなど、その国にある組織を表す。",
  146. "拠点(BCT)\n砦や関所などの軍用拠点の他、市場や街道など、その国にある拠点を表す。",
  147. "文化(CCT)\n食のバリエーションが多い、森に造詣が深いなどのその国の文化や風習を表す。",
  148. ]
  149. ),
  150. "TCT" => DiceTable::D66HalfGridTable.new(
  151. "国特徴・地形表",
  152. [
  153. "水辺\nあなたの国は大河や海洋に面しており、水運の便に優れている。\n技術+2、資金+1",
  154. "森林\nあなたの国には大きな森がいくつもある。ただ風光明媚なだけでなく、木材資源にも恵まれている。\n森林+3",
  155. "山岳\nあなたの国は大きな山に囲まれている。山は国にさまざまな実りをもたらしてくれる。\n鉱物+2、森林+1",
  156. "草原\nあなたの国は見渡す限りの大草原から構成されている。馬を育てたり交易を行なうには、絶好の土地と言えるだろう。\n食料+1、馬+2",
  157. "沼地\nあなたの国は小さな川と、それが流れ込む池や沼地から構成されている。\n食料+2、森林+1",
  158. "荒野\nあなたの国のほとんどは荒野からなっている。野生のごつごつした荒々しさが国土の特徴だ。\n鉱物+2、馬+2、資金-1",
  159. ],
  160. [
  161. "砂漠\nあなたの国は砂漠に取り巻かれている。灼熱の昼と極寒の夜があなたたちの日常だ。\n技術+2、資金+2、森林-1",
  162. "寒冷地\nあなたの国は雪と氷を友としている。夏は短く、冬は長い。鉛色の雲の下であなたたちは育った。\n鉱物+2、資金+1",
  163. "熱帯雨林\nあなたの国は焦熱の地である。雨期になれば大量の雨が降り注ぎ、巨大な密林を構成する。\n食料+1、森林+2",
  164. "火山\nあなたの国は火山地帯にある。山は火を噴き大地を揺らすが、それ故の豊かさもある。\n鉱物+3",
  165. "諸島群\nあなたの国はいくつもの小さな島によって構成されている。交易にこれほど適した土地もないだろう。\n資金+3",
  166. "秘境\nあなたの国は、混沌の影響によってこの世ならぬ光景を持っている。空を飛ぶ島や形を取った虹などだ。商才はGMと相談せよ。\n国資源ひとつを+3",
  167. ]
  168. ),
  169. "ICT" => DiceTable::D66HalfGridTable.new(
  170. "国特徴・産業表",
  171. [
  172. "農業\nあなたの国は農業生産力に優れている。大地の恵みが国の基だ。\n食料+3",
  173. "手工業\nあなたの国は織物や細工物といった人間の手作業から生み出される道具作りに秀でている。\n技術+3",
  174. "鉱業\nあなたの国は大地そのものに眠る鉱物資源が豊富なことで知られている。\n鉱物+4、森林-1",
  175. "牧畜\nあなたの国は広大な領地を生かして、牛や馬のような牧畜産業が豊かである。\n食料+1、馬+2",
  176. "漁業\nあなたの国は海または河川を生かした大規模な漁業で名を轟かせている。\n技術+1、食料+2",
  177. "貿易\nあなたの国は国と国とを結びつけ、その仲立ちをして利益を得ている。\n資金+3",
  178. ],
  179. [
  180. "金融\nあなたの国は他社の金を預かり、その金を貸し付けることで富を得ている。\n資金+3",
  181. "金属加工\nあなたの国は刀剣鍛冶や金細工といった、金属を加工して別の何かに変える産業を有している。\n技術+2、鉱物+2、森林-1",
  182. "ガラス\nあなたの国はガラス工芸技術を保持している。列国でも稀な技術だ。\n技術+2、資金+2、森林-1",
  183. "香辛料\nあなたの国は胡椒や唐辛子のようなスパイスの産地である。\n食料+1、資金+2",
  184. "酒造\nあなたの国は葡萄酒や蜂蜜酒のようなアルコールの産地として知られている。\n食料+2、資金+1",
  185. "サービス業\nあなたの国は演劇や酒場、レストランといった文化的な産業で名を馳せている。\n技術+1、資金+2",
  186. ]
  187. ),
  188. "PCT" => DiceTable::D66HalfGridTable.new(
  189. "国特徴・人物表",
  190. [
  191. "哲学者\nあなたの国には高名な哲学者がいる。あなたの国には知的な国家だと考えられている。\n技術+1、資金+2",
  192. "科学者\nあなたの国には混沌に立ち向かう科学者(メイジではない)がおり、技術に優れている。\n技術+3",
  193. "高名な騎士\nあなたの国には高名な騎士がおり、その武勇を慕ってさまざまな武芸者が集まってくる。\n技術+1、",
  194. "芸能者\nあなたの国には偉大な芸術家や歌姫がおり、その人気は他国にも響いている。\n技術+1、資金+2",
  195. "大商人\nあなたの国に居を構えている大商人の富は、一国にも匹敵する。その税収はばかにならない。\n資金+3",
  196. "聖人\nあなたの国には聖人と呼ばれる偉大な宗教的指導者がいる。その名声は素晴らしい。\n食料+2、資金+1",
  197. ],
  198. [
  199. "森林官\nあなたの国には森林資源を管理する森林官がおり、その技術を弟子たちに分け与えている。\n森林+3",
  200. "名工\nあなたの国には非常に優秀な鍛冶職人がおり、その技術を弟子たちに分け与えている。\n技術+2、資金+1",
  201. "売国奴\nあなたの国には極めて油断ならない臣下がいる。大変有能だが、裏切りを考えていることは明白なのだ。\n資金+4、技術-1",
  202. "農民指導者\nあなたの国には農民たちを指導する偉大な英雄がいる。彼は常に農民の味方だ。\n食料+3",
  203. "亡命者\nあなたの国には他国から亡命してきた優秀な技術者がいる。その事がいずれ災厄を呼び込むかもしれない\n国資源ふたつに+2",
  204. "かつての英雄\nあなたの国土の一部は、かつての英雄たるアーティストと融合している。彼は時折あなたに力を貸してくれる。\n食料に+1、森林+2",
  205. ]
  206. ),
  207. "OCT" => DiceTable::D66HalfGridTable.new(
  208. "国特徴・組織表",
  209. [
  210. "運搬業者\nあなたの国には水運や運搬など、輸送に携わる人々が多い。\n食料+3",
  211. "職人学校\nあなたの国は技術を伝授し発展させる学校を有している。\n技術+3",
  212. "森番\nあなたの国は森を守るための独自の警察を有している。\n森林+3",
  213. "金掘り衆\nあなたの国はいわゆる山師を組織化しており、鉱山開発に熱心だ。\n鉱物+3",
  214. "民会\nあなたの国は豪商や大農場主からなる議会を持ち、意見を取り入れている。\n資金+3",
  215. "飛脚\nあなたの国は飛脚や早馬といった高速通信網が発達している。\n馬+3",
  216. ],
  217. [
  218. "放浪民\nあなたの国には、騎馬民族や放浪民といった人々が訪れることが多い。\n馬+2、資金+1",
  219. "宗教結社\nあなたの国には巨大な宗教結社が存在する。悩んだらクレスト教団とせよ。\n技術+2、資金+1",
  220. "学術団体\nあなたの国にはアカデミーの分校、あるいは何らかの研究施設が存在する。\n食料+1、技術+2",
  221. "異民族\nあなたの国には主流民族とは別の異民族が発生しており、目下のところ共存している。\n技術+1、資金+2",
  222. "難民\nあなたの国には他国の戦乱を逃れてきた難民たちが避難してきている。しかし、安価な労働力の供給源であることも確かだ。\n食料-2、技術+2、資金+3",
  223. "犯罪結社\nあなたの国は豊かで、それゆえに犯罪結社が跳梁している。\n資金+3",
  224. ]
  225. ),
  226. "BCT" => DiceTable::D66HalfGridTable.new(
  227. "国特徴・拠点表",
  228. [
  229. "城塞\nあなたの首都はその難攻不落の防壁で知られている。\n技術+3",
  230. "長城\nあなたの国境線は堅牢な長城で守られている。それが国境線の全域に及ぶかどうかはGMと相談せよ。\n技術+2、資金+1",
  231. "良港\nあなたの国には誰もがうらやむ非常に安定した広い港がある。\n資金+3",
  232. "運河\nあなたの国には巨大な運河があり、人々に流通と治水とをもたらしている。\n食料+2、技術+1",
  233. "図書館\nあなたの国には図書館があり、膨大な知識を過去から蓄積している。\n技術+3",
  234. "訓練所\nあなたの国には訓練所があり、兵士たちを常に鍛えることができる。\n技術+2、馬+1",
  235. ],
  236. [
  237. "下町\nあなたの国には貧しい人々が住まう下町(悪い言い方をすれば貧民街)がある。豊かではないが、そこには活気がある。\n食料+2、資金+1",
  238. "高級住宅街\nあなたの国には豊かな人々が多く、そこに住みたいと考える人も多い。\n資金+3",
  239. "保養地\nあなたの国には風光明媚で過ごしやすい土地がある。外国人であっても、そこで休暇を取ることを好むのだ。\n森林+1、資金+2",
  240. "宗教的聖地\nあなたの国には、それに実際的な効果があるかどうかはともかく宗教的な聖地があり、人々を集めている。\n食料+2、森林+1",
  241. "鉱山街\nあなたの国には鉱山があり、その鉱山で働く人たちのための酒場や学校や病院が完備されている。\n鉱物+3",
  242. "歓楽街\nあなたの国は楽しく過ごせる酒場や劇場といったもので評判だ。人々の笑顔がさらなる富をもたらすのだ。\n食料+1、資金+2",
  243. ]
  244. ),
  245. "CCT" => DiceTable::D66HalfGridTable.new(
  246. "国特徴・文化表",
  247. [
  248. "芸術指向\nあなたの国の人々は芸術に高い価値を与えている。\n資金+3",
  249. "享楽的\nあなたの国民は、今日を楽しく過ごすことが大切だと考えている。\n食料+1、資金+2",
  250. "禁欲的\nあなたの国民は、道徳を重んじ、常に自分の欲望を制限することが理想的だと考えている。\n食料+4、資金-1",
  251. "好戦的\nあなたの国民は好戦的だ。物事は剣と暴力によって解決するべきだと考えている。\n技術+1、馬+2",
  252. "平和主義\nあなたの国民は平和を愛している。まず話し合うことが大事だと思っているのだ。\n食料+1、森林+2",
  253. "理知的\nあなたの国民は論理性を重んじる。道理が通っているかが問題だ。\n技術+3",
  254. ],
  255. [
  256. "情念深い\nあなたの国民は感情を重視する。恩は忘れず、恨みもまた決して忘れない。\n鉱物+1、森林+2",
  257. "礼儀重視\nあなたの国民は建前としての礼儀を重んじる。礼儀こそ平和と繁栄への道だ。\n技術+2、馬+1",
  258. "拝金主義\nあなたの国民にとって、もっとも重要なのは金である。金がなくてどうして生きて行けよう。\n森林-1、資金+4",
  259. "農本主義\nあなたの国では農民が国の基である。大地を耕すことが理想的なのだ。\n食料+3",
  260. "富国強兵\nあなたの国は技術を発展させ軍隊を近代化させるべく一丸となっている。\n技術+2、馬+1",
  261. "呑気\nあなたの国は豊かだ。人々は思い煩うことなく、日々をのんびりと楽しく生きている。\n技術-1、食料+4",
  262. ]
  263. ),
  264. }.freeze
  265. 1 ALIASES = {
  266. "PositiveFT" => "PFT",
  267. "NegativeFT" => "NFT",
  268. "CategoryCT" => "CT",
  269. }.transform_keys(&:upcase).freeze
  270. 1 register_prefix(TABLES.keys, ALIASES.keys)
  271. end
  272. end
  273. end

lib/bcdice/game_system/GundamSentinel.rb

96.88% lines covered

88.1% branches covered

128 relevant lines. 124 lines covered and 4 lines missed.
42 total branches, 37 branches covered and 5 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class GundamSentinel < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'GundamSentinel'
  7. # ゲームシステム名
  8. 1 NAME = 'ガンダム・センチネルRPG'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'かんたむせんちねる'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・基本戦闘(BB, BBM)
  14.  BB[+修正][>回避値]で基本戦闘を判定します。回避値を指定すると、命中・回避も表示します。
  15.  BBM[+修正][>回避値]でモブ用の基本戦闘を判定します。クリティカルを判定します。回避値を指定すると、命中・回避も表示します。
  16.  例)BB BBM BB+5>14 BBM+5>15
  17. ・一般技能(GS)
  18.  GS[+修正][>目標値]で一般技能を判定します。目標値を指定しない場合は、目標値10で判定します。
  19.  例)GS GS+5 GS+5>10
  20. ・各種表
  21.  敵MSクリティカルヒットチャート (ECHC)
  22.  PC用脱出判定チャート      (PEJC[+m] m:修正)
  23.  艦船追加ダメージ決定チャート  (ASDC)
  24.  対空砲結果チャート       (AARC[+m]=t m:修正, t:対空防御力)
  25.  リハビリ判定チャート      (RTJC[+m] m:修正)
  26.  二次被害判定チャート      (SDDC)
  27. INFO_MESSAGE_TEXT
  28. 1 def initialize(command)
  29. 34 super(command)
  30. 34 @round_type = RoundType::CEIL
  31. 34 @d66_sort_type = D66SortType::NO_SORT
  32. end
  33. 1 def eval_game_system_specific_command(command)
  34. 34 roll_basic_battle(command) ||
  35. roll_general_skill(command) ||
  36. roll_anti_aircraft_gun_result_chart(command) ||
  37. roll_escape_chart(command) ||
  38. roll_rehabilitation_chart(command) ||
  39. roll_tables(command, TABLES)
  40. end
  41. 1 private
  42. # 基本戦闘ロール
  43. 1 def roll_basic_battle(command)
  44. 34 m = /^BB(M)?([-+][-+\d]+)?(>([-+\d]+))?/.match(command)
  45. 34 else: 9 then: 25 return nil unless m
  46. 9 mob = m[1]
  47. 9 modify = ArithmeticEvaluator.eval(m[2])
  48. 9 have_modify = false
  49. 9 then: 6 else: 3 have_modify = true if m[2]
  50. 9 avoid = ArithmeticEvaluator.eval(m[4])
  51. 9 have_avoid = false
  52. 9 then: 4 else: 5 have_avoid = true if m[4]
  53. 9 d60 = @randomizer.roll_once(6)
  54. 9 d06 = @randomizer.roll_once(6)
  55. 9 total_d = d60 * 10 + d06
  56. 9 d60 += (d06 + modify - 1).div(6)
  57. 9 d06 = (d06 + modify - 1).modulo(6) + 1
  58. 9 total = d60 * 10 + d06
  59. 9 then: 1 else: 8 total = 11 if total < 11
  60. 9 success = false
  61. 9 failure = false
  62. 9 critical = false
  63. 9 modify_label = nil
  64. 9 then: 6 else: 3 if have_modify
  65. 6 then: 5 if modify >= 0
  66. 5 modify_label = "#{total_d}+#{modify}"
  67. else: 1 else
  68. 1 modify_label = "#{total_d}#{modify}"
  69. end
  70. end
  71. 9 critical_label = nil
  72. 9 then: 2 else: 7 if mob && (total >= 66)
  73. 2 critical_label = "クリティカル"
  74. 2 critical = true
  75. end
  76. 9 result = nil
  77. 9 then: 4 else: 5 if have_avoid
  78. 4 then: 3 if total > avoid
  79. 3 result = "命中(+" + count_success(total, avoid).to_s + ")"
  80. 3 success = true
  81. else: 1 else
  82. 1 result = "回避"
  83. 1 failure = true
  84. end
  85. end
  86. sequence = [
  87. 9 "(#{command})",
  88. modify_label,
  89. total,
  90. result,
  91. critical_label,
  92. ].compact
  93. 9 Result.new(sequence.join(" > ")).tap do |r|
  94. 9 r.success = success
  95. 9 r.failure = failure
  96. 9 r.critical = critical
  97. end
  98. end
  99. 1 def count_success(dice, avoid)
  100. 3 d60 = dice.div(10)
  101. 3 d06 = dice.modulo(10)
  102. 3 a60 = avoid.div(10)
  103. 3 a06 = avoid.modulo(10)
  104. 3 return ((d60 * 6 + d06) - (a60 * 6 + a06))
  105. end
  106. # 一般技能ロール
  107. 1 def roll_general_skill(command)
  108. 25 m = /^GS([-+][-+\d]+)?(>([-+\d]+))?/.match(command)
  109. 25 else: 4 then: 21 return nil unless m
  110. 4 modify = ArithmeticEvaluator.eval(m[1])
  111. 4 have_modify = false
  112. 4 then: 0 else: 4 have_modify = true if m[1]
  113. 4 target = ArithmeticEvaluator.eval(m[3])
  114. 4 else: 2 then: 2 target = 10 unless m[3]
  115. 4 success = false
  116. 4 failure = false
  117. 4 dice = @randomizer.roll_sum(2, 6)
  118. 4 modify_label = nil
  119. 4 then: 0 else: 4 if have_modify
  120. then: 0 if modify >= 0
  121. modify_label = "#{dice}+#{modify}"
  122. else: 0 else
  123. modify_label = "#{dice}#{modify}"
  124. end
  125. end
  126. 4 total = dice + modify
  127. 4 then: 2 if total > target
  128. 2 result = "成功"
  129. 2 success = true
  130. else: 2 else
  131. 2 result = "失敗"
  132. 2 failure = true
  133. end
  134. sequence = [
  135. 4 "(#{command})",
  136. modify_label,
  137. total,
  138. result,
  139. ].compact
  140. 4 Result.new(sequence.join(" > ")).tap do |r|
  141. 4 r.success = success
  142. 4 r.failure = failure
  143. end
  144. end
  145. # 各種表
  146. # 対空砲結果チャート
  147. GUN_RESULT_CHART = [
  148. 1 ["D", "H", "H", "H", 10, 8, 6, 5, 4, 2, 1, "-", "-"],
  149. ["D", "H", "H", "H", 12, 10, 9, 8, 6, 5, 3, 2, "-"],
  150. ["D", "D", "H", "H", "H", 12, 10, 9, 7, 6, 4, 3, 1],
  151. ["D", "D", "H", "H", "H", 14, 13, 12, 10, 8, 6, 5, 3],
  152. ["D", "D", "D", "H", "H", "H", 14, 13, 11, 9, 7, 6, 4],
  153. ["D", "D", "D", "H", "H", "H", "H", 16, 14, 12, 11, 8, 6],
  154. ].freeze
  155. 1 def roll_anti_aircraft_gun_result_chart(command)
  156. 21 parser = Command::Parser.new("AARC", round_type: @round_type).restrict_cmp_op_to(:==)
  157. 21 parsed = parser.parse(command)
  158. 21 else: 6 then: 15 return nil unless parsed
  159. 6 target = parsed.target_number.clamp(1, 6)
  160. 6 dice = @randomizer.roll_sum(2, 6)
  161. 6 total = (dice + parsed.modify_number).clamp(1, 13)
  162. cmd =
  163. 6 then: 4 if parsed.modify_number != 0
  164. 4 "(#{dice}#{Format.modifier(parsed.modify_number)}=#{total})"
  165. else: 2 else
  166. 2 total.to_s
  167. end
  168. 6 result = GUN_RESULT_CHART[target - 1][total - 1]
  169. 6 Result.new().tap do |r|
  170. 6 r.text = "対空砲結果チャート(#{cmd}vs#{target}) > 結果「#{result}」"
  171. 6 r.condition = result.is_a?(Integer)
  172. end
  173. end
  174. # PC用脱出判定チャート
  175. 1 ESCAPE_CHART = [
  176. '*',
  177. '*',
  178. '無傷で脱出',
  179. '無傷で脱出',
  180. '無傷で脱出',
  181. '軽傷で脱出「1D6ダメージ。」',
  182. '中傷で脱出「2D6ダメージ。」',
  183. '重傷で脱出「3D6ダメージ。」',
  184. '重体で脱出「1D3の耐久力が残る。」',
  185. '戦死「二階級特進。」',
  186. '戦死「二階級特進。」',
  187. '戦死「二階級特進。」',
  188. '戦死「二階級特進。」',
  189. ].freeze
  190. 1 def roll_escape_chart(command)
  191. 15 parser = Command::Parser.new("PEJC", round_type: @round_type).restrict_cmp_op_to(nil)
  192. 15 parsed = parser.parse(command)
  193. 15 else: 3 then: 12 return nil unless parsed
  194. 3 dice = @randomizer.roll_sum(2, 6)
  195. 3 total = (dice + parsed.modify_number).clamp(2, 12)
  196. cmd =
  197. 3 then: 0 if parsed.modify_number != 0
  198. "#{dice}#{Format.modifier(parsed.modify_number)}=#{total}"
  199. else: 3 else
  200. 3 total.to_s
  201. end
  202. 3 result = ESCAPE_CHART[total]
  203. 3 Result.new("PC用脱出判定チャート(#{cmd}) > #{result}")
  204. end
  205. 1 REHABILITATION_CHART = [
  206. '*',
  207. '*',
  208. 'なし',
  209. '1ヶ月',
  210. '2ヶ月',
  211. '3ヶ月',
  212. '4ヶ月',
  213. '5ヶ月',
  214. '6ヶ月',
  215. '10ヶ月',
  216. '1年',
  217. '1年6ヶ月',
  218. '1年と、もう一度このチャートで振った結果分を足した期間',
  219. ].freeze
  220. 1 def roll_rehabilitation_chart(command)
  221. 12 parser = Command::Parser.new("RTJC", round_type: @round_type).restrict_cmp_op_to(nil)
  222. 12 parsed = parser.parse(command)
  223. 12 else: 3 then: 9 return nil unless parsed
  224. 3 dice = @randomizer.roll_sum(2, 6)
  225. 3 total = (dice + parsed.modify_number).clamp(2, 12)
  226. cmd =
  227. 3 then: 1 if parsed.modify_number != 0
  228. 1 "#{dice}#{Format.modifier(parsed.modify_number)}=#{total}"
  229. else: 2 else
  230. 2 total.to_s
  231. end
  232. 3 result = REHABILITATION_CHART[total]
  233. 3 Result.new("リハビリ判定チャート(#{cmd}) > #{result}")
  234. end
  235. TABLES = {
  236. 1 'ECHC' => DiceTable::Table.new(
  237. '敵MSクリティカルヒットチャート',
  238. '2D6',
  239. [
  240. 'コックピット直撃:目標MSは残骸となる。',
  241. '腕破損:同時に携帯武器も失う。携帯武装の交換も行えない。直ちにモラル判定を-4で行う。',
  242. '射撃武装破損:目標MSはその時点で使用しているナンバーの若い武装を1つ失う。全ての武装を失った場合、モラル判定を行う。',
  243. '頭部直撃:目標MSはメインカメラを失い、以後射撃、格闘の命中判定に-6の修正を受ける。頭部に装備されている武装も失われる。',
  244. 'パイロット気絶:目標MSは回復するまで行動不能。',
  245. '目標MSへのダメージ2倍。',
  246. '目標MSへのダメージ2倍。',
  247. '目標MSへのダメージ3倍。',
  248. '脚破損:目標MSは、以後の回避値に-6の修正を受ける。',
  249. 'コントロール不能:目標MSは1D6ラウンドの間、行動不能。',
  250. '熱核ジェネレーター直撃:目標MSは直ちに爆発(耐久力0)する。',
  251. ]
  252. ),
  253. 'ASDC' => DiceTable::Table.new(
  254. '艦船追加ダメージ決定チャート',
  255. '2D6',
  256. [
  257. 'ブリッジ損傷「複数ある艦は、総てのブリッジが損傷すると以後の対空防御は修正を+5する。」',
  258. 'カタパルト損傷「複数ある艦は、総てのカタパルトが損傷すると、MSの発着艦ができなくなる。」',
  259. '追加ダメージ「追加2D6×2ダメージ。」',
  260. '主砲大破「主砲1門を失う。」',
  261. '副砲大破「副砲1門を失う。」',
  262. '追加ダメージ「追加2D6ダメージ。」',
  263. '追加ダメージ「追加2D6ダメージ。」',
  264. '追加ダメージ「追加2D6ダメージ。」',
  265. '1ターン行動不能「1ターンはその艦は何も行動ができない。」',
  266. '航行不能「その艦はそのヘックスから動けなくなる。」',
  267. 'エンジン誘爆「1D6×10%の耐久力を失う。」',
  268. ]
  269. ),
  270. 'SDDC' => DiceTable::D66GridTable.new(
  271. '二次被害判定チャート',
  272. [
  273. [
  274. '奇蹟的に無傷「不発!?今回のダメージは0。」',
  275. 'メインカメラ破損「以後、射撃、格闘の命中判定に-3の修正を受ける。」',
  276. 'コクピット破損「以後の追加ダメージ判定に-1の修正を受ける。」',
  277. '右腕損傷「携帯していた武装も失う。また右腕での武器の使用はできなくなる。」',
  278. '左腕損傷「携帯していた武装も失う。また左腕での武器の使用はできなくなる。」',
  279. '気絶「気絶判定の余地無く、必ず気絶する。」',
  280. ],
  281. [
  282. '気絶「気絶判定を-6の修正で行う。」',
  283. '気絶「気絶判定を-4の修正で行う。」',
  284. '気絶「気絶判定を-2の修正で行う。」',
  285. '気絶「気絶判定を行う。」',
  286. '予備弾倉破損「携帯している予備弾倉かEパックを1つ失う。」',
  287. 'サブカメラ破損「以後、射撃、格闘の命中判定に-1の修正を受ける。」',
  288. ],
  289. [
  290. '固定武装破損「固定されている武装を1つ失う。」',
  291. '予備武装破損「携帯している以外の武装を1つ失う。」',
  292. '頭部破損「メインカメラも失い、以後、射撃、格闘の命中判定に-3の修正を受ける。」',
  293. '右脚破損「以後、回避値が1D3低下する。」',
  294. '左脚破損「以後、回避値が1D3低下する。」',
  295. '操縦機構破損「以後、すべての行動は消費行動ポイントを1ポイント余分に消費する。」',
  296. ],
  297. [
  298. '軽傷「パイロットは1D6のダメージを受ける。また気絶判定を行う。」',
  299. '中傷「パイロットは2D6のダメージを受ける。また気絶判定を-6修正で行う。」',
  300. '重傷「パイロットは3D6のダメージを受ける。また気絶判定を-9修正で行う。」',
  301. '操縦伝達部破損「以後すべての射撃、格闘の命中判定と回避値に-1の修正を受ける。」',
  302. 'センサー破損「イニシアティブ決定に-1の修正を受ける。」',
  303. '脱出機構破損「脱出判定に+3の修正を受ける。」',
  304. ],
  305. [
  306. '熱核ジェネレーター損傷「行動の「追加移動」が行えなくなる。」',
  307. '右腕の携帯武装破損「右腕に持っていた武装を1つ失う。」',
  308. '左腕の携帯武装破損「左腕に持っていた武装を1つ失う。」',
  309. 'サブスラスター破損「回避値が1低下する。」',
  310. 'プロペラントタンク破損「プロペラントタンクを1つ失う。」',
  311. 'バックパック破損「推進剤3D6ポイント失う。」',
  312. ],
  313. [
  314. 'メインスラスター破損「回避値が1D6低下する。」',
  315. '動力パイプ破損「以後、行動ポイント決定のダイスに-1の修正を受ける。」',
  316. '動力伝達機構破損「以後、行動ポイント決定のサイコロに-1D3の修正を受ける。」',
  317. 'サブスラスター破損「旋回が120度までしかできなくなる。」',
  318. 'メインスラスター破損「旋回が60度までしかできなくなる。」',
  319. '熱核ジェネレーター直撃「そのMSは爆発する。PCは直ちに脱出判定を行う。」',
  320. ]
  321. ]
  322. ),
  323. }.freeze
  324. 1 register_prefix('BBM?', 'GS', 'AARC', 'PEJC', 'RTJC', TABLES.keys)
  325. end
  326. end
  327. end

lib/bcdice/game_system/Gundog.rb

96.3% lines covered

81.25% branches covered

27 relevant lines. 26 lines covered and 1 lines missed.
16 total branches, 13 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Gundog < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Gundog'
  7. # ゲームシステム名
  8. 1 NAME = 'ガンドッグ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'かんとつく'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. 失敗、成功、クリティカル、ファンブルとロールの達成値の自動判定を行います。
  14. nD9ロールも対応。
  15. INFO_MESSAGE_TEXT
  16. 1 def initialize(command)
  17. 270 super(command)
  18. 270 @enabled_d9 = true
  19. end
  20. # ゲーム別成功度判定(1d100)
  21. 1 def result_1d100(total, _dice_total, cmp_op, target)
  22. 18 else: 16 then: 2 return nil unless cmp_op == :<=
  23. 16 then: 4 if total >= 100
  24. 4 else: 12 Result.fumble("ファンブル")
  25. 12 then: 4 elsif total <= 1
  26. 4 else: 8 Result.critical("絶対成功(達成値1+SL)")
  27. 8 then: 0 elsif target == "?"
  28. else: 8 Result.nothing
  29. 8 then: 6 elsif total <= target
  30. 6 dig10 = total / 10
  31. 6 dig1 = total - dig10 * 10
  32. 6 then: 0 else: 6 dig10 = 0 if dig10 >= 10
  33. 6 then: 0 else: 6 dig1 = 0 if dig1 >= 10 # 条件的にはあり得ない(笑
  34. 6 then: 4 if dig1 <= 0
  35. 4 Result.critical("クリティカル(達成値20+SL)")
  36. else: 2 else
  37. 2 Result.success("成功(達成値#{dig10 + dig1}+SL)")
  38. end
  39. else: 2 else
  40. 2 Result.failure("失敗")
  41. end
  42. end
  43. end
  44. end
  45. end

lib/bcdice/game_system/GundogRevised.rb

93.51% lines covered

79.49% branches covered

77 relevant lines. 72 lines covered and 5 lines missed.
39 total branches, 31 branches covered and 8 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/Gundog'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class GundogRevised < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'GundogRevised'
  8. # ゲームシステム名
  9. 1 NAME = 'ガンドッグ・リヴァイズド'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'かんとつくりうあいすと'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. 失敗、成功、クリティカル、ファンブルとロールの達成値の自動判定を行います。
  15. nD9ロールも対応。
  16. ・ダメージペナルティ表  (~DPTx) (x:修正)
  17.  射撃(SDPT)、格闘(MDPT)、車両(VDPT)、汎用(GDPT)の各表を引くことが出来ます。
  18.  修正を後ろに書くことも出来ます。
  19. ・ファンブル表      (~FTx) (x:修正)
  20.  射撃(SFT)、格闘(MFT)、投擲(TFT)の各表を引くことが出来ます。
  21.  修正を後ろに書くことも出来ます。
  22. INFO_MESSAGE_TEXT
  23. 1 register_prefix('.DPT', '.FT')
  24. 1 def initialize(command)
  25. 36 super(command)
  26. 36 @enabled_d9 = true
  27. end
  28. # ---- 以降、Gundog.rbよりほぼコピペ(絶対成功→ベアリーに用語変更対応の為、継承だと不都合)
  29. # ゲーム別成功度判定(1d100)
  30. 1 def result_1d100(total, _dice_total, cmp_op, target)
  31. 10 else: 9 then: 1 return nil unless cmp_op == :<=
  32. 9 then: 2 if total >= 100
  33. 2 else: 7 Result.fumble("ファンブル")
  34. 7 then: 2 elsif total <= 1
  35. 2 else: 5 Result.critical("ベアリー(達成値1+SL)")
  36. 5 then: 0 elsif target == "?"
  37. else: 5 Result.nothing
  38. 5 then: 3 elsif total <= target
  39. 3 dig10 = total / 10
  40. 3 dig1 = total - dig10 * 10
  41. 3 then: 0 else: 3 dig10 = 0 if dig10 >= 10
  42. 3 then: 0 else: 3 dig1 = 0 if dig1 >= 10 # 条件的にはあり得ない(笑
  43. 3 then: 1 if dig1 <= 0
  44. 1 Result.critical("クリティカル(達成値20+SL)")
  45. else: 2 else
  46. 2 Result.success("成功(達成値#{dig10 + dig1}+SL)")
  47. end
  48. else: 2 else
  49. 2 Result.failure("失敗")
  50. end
  51. end
  52. 1 def eval_game_system_specific_command(command)
  53. 24 string = command.upcase
  54. 24 table = []
  55. 24 ttype = ""
  56. 24 type = ""
  57. 24 mod = 0
  58. # ダメージペナルティ表
  59. 24 then: 15 else: 9 if /(\w)DPT([+\-\d]*)/i =~ string
  60. 15 ttype = 'ダメージペナルティー'
  61. 15 head = Regexp.last_match(1)
  62. 15 then: 15 else: 0 mod = ArithmeticEvaluator.eval(Regexp.last_match(2)) if Regexp.last_match(2)
  63. 15 type, table = getDamageTypeAndTable(head)
  64. end
  65. # ファンブル表
  66. 24 then: 9 else: 15 if /(\w)FT([+\-\d]*)/i =~ string
  67. 9 ttype = 'ファンブル'
  68. 9 head = Regexp.last_match(1)
  69. 9 then: 9 else: 0 mod = ArithmeticEvaluator.eval(Regexp.last_match(2)) if Regexp.last_match(2)
  70. 9 type, table = getFumbleTypeAndTable(head)
  71. end
  72. 24 then: 0 else: 24 return '1' if type.empty?
  73. 24 diceArray = @randomizer.roll_barabara(2, 10)
  74. 72 dice = mod + diceArray.select { |x| x < 10 }.sum()
  75. 24 diceOriginalText = dice
  76. 24 then: 2 else: 22 dice = 0 if dice < 0
  77. 24 then: 2 else: 22 dice = 18 if dice > 18
  78. 24 output = "#{type}#{ttype}表[#{diceOriginalText}] > #{table[dice]}"
  79. 24 return output
  80. end
  81. 1 def getDamageTypeAndTable(head)
  82. 15 case head
  83. when: 6 when "S"
  84. 6 type = '射撃'
  85. # 射撃ダメージペナルティー表
  86. 6 table = [
  87. '対象は[死亡]', # 0
  88. '[追加D]4D6/[出血]2D6/[重傷]-40%/[朦朧判定]15', # 1
  89. '[追加D]3D6/[出血]2D6/[重傷]-30%/[朦朧判定]14', # 2
  90. '[追加D]3D6/[出血]2D6/[重傷]-30%/[朦朧判定]13', # 3
  91. '[追加D]3D6/[出血]1D6/[重傷]-20%/[朦朧判定]12', # 4
  92. '[追加D]2D6/[出血]1D6/[重傷]-20%/[朦朧判定]11', # 5
  93. '[追加D]2D6/[軽傷]-20%/[朦朧判定]11', # 6
  94. '[追加D]2D6/[軽傷]-20%/[朦朧判定]10', # 7
  95. '[追加D]2D6/[軽傷]-20%/[朦朧判定]8', # 8
  96. '[追加D]2D6/[軽傷]-20%/[朦朧判定]6', # 9
  97. '[追加D]2D6/[軽傷]-20%/[朦朧判定]4', # 10
  98. '[追加D]2D6/[軽傷]-20%', # 11
  99. '[追加D]1D6/[軽傷]-20%', # 12
  100. '[追加D]1D6/[軽傷]-10%', # 13
  101. '[ショック]-20%', # 14
  102. '[ショック]-10%', # 15
  103. '[不安定]', # 16
  104. '手に持った武器を落とす。複数ある場合はランダム', # 17
  105. 'ペナルティー無し', # 18
  106. ]
  107. when: 3 when "M"
  108. 3 type = '格闘'
  109. # 格闘ダメージペナルティー表
  110. 3 table = [
  111. '対象は[死亡]', # 0
  112. '[追加D]4D6/[出血]2D6/[重傷]-40%/[朦朧判定]15', # 1
  113. '[追加D]3D6/[出血]2D6/[重傷]-30%/[朦朧判定]14', # 2
  114. '[追加D]3D6/[出血]1D6/[重傷]-20%/[朦朧判定]14/[不安定]', # 3
  115. '[追加D]2D6/[出血]1D6/[重傷]-20%/[朦朧判定]14', # 4
  116. '[追加D]2D6/[重傷]-20%/[朦朧判定]12/[不安定]', # 5
  117. '[追加D]2D6/[軽傷]-20%/[朦朧判定]11', # 6
  118. '[追加D]2D6/[軽傷]-20%/[朦朧判定]10', # 7
  119. '[追加D]2D6/[軽傷]-20%/[朦朧判定]8', # 8
  120. '[追加D]2D6/[軽傷]-20%/[朦朧判定]6', # 9
  121. '[追加D]1D6/[軽傷]-20%/[朦朧判定]6', # 10
  122. '[追加D]1D6/[軽傷]-10%/[朦朧判定]6', # 11
  123. '[追加D]1D6/[軽傷]-10%/[不安定]', # 12
  124. '[追加D]1D6/[軽傷]-10%', # 13
  125. '[ショック]-20%', # 14
  126. '[ショック]-10%', # 15
  127. '[不安定]', # 16
  128. '手に持った武器を落とす。複数ある場合はランダム', # 17
  129. 'ペナルティー無し', # 18
  130. ]
  131. when: 3 when "V"
  132. 3 type = '車両'
  133. # 車両ダメージペナルティー表
  134. 3 table = [
  135. '[クラッシュ]する。[チェイス]から除外', # 0
  136. '[車両D]4D6/[乗員D]3D6/[操作性]-40%/[スピン判定]', # 1
  137. '[車両D]3D6/[乗員D]3D6/[操作性]-30%/[スピン判定]', # 2
  138. '[乗員D]3D6/[操作性]-20%/[スピン判定]', # 3
  139. '[車両D]3D6/[操作性]-20%/[スピン判定]', # 4
  140. '[乗員D]3D6/[操作性]-10%/[スピン判定]', # 5
  141. '[車両D]3D6/[操作性]-10%/[スピン判定]', # 6
  142. '[乗員D]2D6/[スピード]-2/[スピン判定]', # 7
  143. '[車両D]2D6/[スピード]-2/[スピン判定]', # 8
  144. '[乗員D]2D6/[操縦判定]-20%/[スピン判定]', # 9
  145. '[車両D]2D6/[操縦判定]-20%/[スピン判定]', # 10
  146. '[乗員D]2D6/[操縦判定]-20%', # 11
  147. '[車両D]2D6/[操縦判定]-20%', # 12
  148. '[車両D]1D6/[操縦判定]-20%', # 13
  149. '[車両D]1D6/[操縦判定]-10%', # 14
  150. '攻撃が乗員をかすめる。ランダムな乗員1人に[ショック]-20%', # 15
  151. '攻撃が乗員に当たりかける。ランダムな乗員1人に[ショック]-10%', # 16
  152. '車両が蛇行。乗員全員は〈運動〉判定。失敗で[不安定]', # 17
  153. 'ペナルティー無し', # 18
  154. ]
  155. when: 3 when "G"
  156. 3 type = '汎用'
  157. # 汎用ダメージペナルティー表
  158. 3 table = [
  159. '対象は[死亡]', # 0
  160. '[追加D]4D6/[出血]2D6/[重傷]-40%/[朦朧判定]15', # 1
  161. '[追加D]3D6/[出血]2D6/[重傷]-30%/[朦朧判定]14', # 2
  162. '[追加D]2D6/[出血]1D6/[重傷]-30%/[朦朧判定]13/[不安定]', # 3
  163. '[追加D]2D6/[出血]1D6/[重傷]-30%/[朦朧判定]12', # 4
  164. '[追加D]2D6/[重傷]-20%/[朦朧判定]12/[不安定]', # 5
  165. '[追加D]1D6/[重傷]-20%/[朦朧判定]11', # 6
  166. '[追加D]1D6/[軽傷]-30%/[朦朧判定]10', # 7
  167. '[追加D]1D6/[軽傷]-30%/[朦朧判定]8', # 8
  168. '[追加D]1D6/[軽傷]-30%/[朦朧判定]6', # 9
  169. '[追加D]1D6/[軽傷]-20%/[朦朧判定]6', # 10
  170. '[軽傷]-20%/[朦朧判定]6', # 11
  171. '[軽傷]-20%/[不安定]', # 12
  172. '[軽傷]-20%', # 13
  173. '[軽傷]-10%', # 14
  174. '[ショック]-20%', # 15
  175. '[ショック]-10%', # 16
  176. '[不安定]', # 17
  177. 'ペナルティー無し', # 18
  178. ]
  179. else: 0 else
  180. head = "S" # 間違ったら射撃扱い
  181. type, table = getDamageTypeAndTable(head)
  182. end
  183. 15 return type, table
  184. end
  185. 1 def getFumbleTypeAndTable(head)
  186. 9 case head
  187. when: 3 when "S"
  188. 3 type = '射撃'
  189. # 射撃ファンブル表
  190. 3 table = [
  191. '銃器が暴発、自分に命中。[貫通D]。武装喪失', # 0
  192. '銃器が暴発、自分に命中。[非貫通D]。武装喪失', # 1
  193. '誤射。射線に最も近い味方に命中。[貫通D]', # 2
  194. '誤射。射線に最も近い味方に命中。[非貫通D]', # 3
  195. '銃器が完全に故障。直せない', # 4
  196. '故障。30分かけて〈メカニック〉判定に成功するまで使用不可。', # 5
  197. '故障。〈メカニック〉-20%の判定に成功するまで使用不可。', # 6
  198. '故障。〈メカニック〉判定に成功するまで射撃不可', # 7
  199. '作動不良。[アイテム使用]を2回行って修理するまで射撃不可', # 8
  200. '作動不良。[アイテム使用]を行って修理するまで射撃不可', # 9
  201. '足がもつれて倒れる。[転倒]', # 10
  202. '無理な射撃姿勢で腕を痛める。[軽傷]-20%', # 11
  203. '無理な射撃姿勢でどこかの筋を痛める。[軽傷]-10%', # 12
  204. '武装を落とす。スリング(肩ひも)も切れる', # 13
  205. '武装を落とす。スリング(肩ひも)があれば落とさない', # 14
  206. '排莢された薬莢が服の中に。[ショック]-20%', # 15
  207. '排莢された薬莢が顔に当たる。[ショック]-10%', # 16
  208. '薬莢を踏んで態勢を崩す。[不安定]', # 17
  209. 'ペナルティー無し', # 18
  210. ]
  211. when: 3 when "M"
  212. 3 type = '格闘'
  213. # 格闘ファンブル表
  214. 3 table = [
  215. '自分に命中。[貫通D]', # 0
  216. '自分に命中。[非貫通D]', # 1
  217. '最も近い味方(射程内にいなければ自分)に[貫通D]', # 2
  218. '最も近い味方(射程内にいなければ自分)に[非貫通D]', # 3
  219. '頭を強く打ちつける。[朦朧]', # 4
  220. '武装が壊れる。直せない。[格闘タイプ]なら[重傷]-20%', # 5
  221. '武装がすっぽ抜ける。グレネードの誤差で落下先を決定', # 6
  222. '武装が損傷。30分かけて〈手先〉判定に成功するまで使用不可。[格闘タイプ]なら[重傷]-10%', # 7
  223. '武装がガタつく。〈手先〉判定([格闘タイプ]なら〈強靭〉)に成功するまで使用不可。', # 8
  224. '武装に違和感。[アイテム使用]を行って調整するまで、命中率-20%', # 9
  225. '足がもつれる。[転倒]', # 10
  226. '足がつる。2[ラウンド]の間、移動距離1/2', # 11
  227. '無理な体勢で腕(あるいは脚)を痛める。[軽傷]-20%', # 12
  228. '無理な体勢でどこかの筋を痛める。[軽傷]-10%', # 13
  229. '武装を落とす', # 14
  230. '武装で自分が負傷。[ショック]-20%', # 15
  231. '武装の扱いを間違える。[ショック]-10%', # 16
  232. '攻撃を避けられて体勢を崩す。[不安定]', # 17
  233. 'ペナルティー無し', # 18
  234. ]
  235. when: 3 when "T"
  236. 3 type = '投擲'
  237. # 投擲ファンブル表
  238. 3 table = [
  239. '勢いをつけすぎて転倒し、頭を打つ。[気絶]', # 0
  240. '自分に命中。(手榴弾なら自分の足元に落ちる)[貫通D]', # 1
  241. '自分に命中。(手榴弾なら自分の足元に落ちる)[非貫通D]', # 2
  242. '暴投。射線に最も近い味方に命中。[貫通D]。手榴弾なら新たな中心点からさらに誤差が生じる', # 3
  243. '暴投。射線に最も近い味方に命中。[非貫通D]。手榴弾なら新たな中心点からさらに誤差が生じる', # 4
  244. '頭を強く打ちつける。[朦朧]', # 5
  245. '肩の筋肉断裂。この腕を使う判定に、[重傷]-20%', # 6
  246. 'ヒジの筋肉断裂。この腕を使う判定に、[重傷]-10%', # 7
  247. '肩の筋をひどく痛める。〈医療〉判定に成功するまで、この腕を使う判定に-20%', # 8
  248. '肩の筋を痛める。[行動]を使って休めるまで、この腕を使う判定に-20%', # 9
  249. '腰を痛める。[軽傷]-30%', # 10
  250. '足がもつれて倒れる。[転倒]', # 11
  251. '足がつる。2[ラウンド]の間、移動距離1/2', # 12
  252. '無理な投擲体勢で腕(あるいは脚)を痛める。[軽傷]-20%', # 13
  253. '無理な投擲体勢でどこかの筋を痛める。[軽傷]-10%', # 14
  254. '肩に違和感。[ショック]-20%', # 15
  255. 'ヒジに違和感。[ショック]-10%', # 16
  256. 'つまずいて姿勢を崩す。[不安定]', # 17
  257. 'ペナルティー無し', # 18
  258. ]
  259. else: 0 else
  260. head = "S" # 間違ったら射撃扱い
  261. type, table = getFumbleTypeAndTable(head)
  262. end
  263. 9 return type, table
  264. end
  265. end
  266. end
  267. end

lib/bcdice/game_system/GundogZero.rb

100.0% lines covered

82.61% branches covered

56 relevant lines. 56 lines covered and 0 lines missed.
23 total branches, 19 branches covered and 4 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/Gundog'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class GundogZero < Gundog
  6. # ゲームシステムの識別子
  7. 1 ID = 'GundogZero'
  8. # ゲームシステム名
  9. 1 NAME = 'ガンドッグゼロ'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'かんとつくせろ'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. 失敗、成功、クリティカル、ファンブルとロールの達成値の自動判定を行います。
  15. nD9ロールも対応。
  16. ・ダメージペナルティ表  (〜DPTx) (x:修正)
  17.  射撃(SDPT)、格闘(MDPT)、車両(VDPT)、汎用(GDPT)の各表を引くことが出来ます。
  18.  修正を後ろに書くことも出来ます。
  19. ・ファンブル表      (〜FTx) (x:修正)
  20.  射撃(SFT)、格闘(MFT)、投擲(TFT)の各表を引くことが出来ます。
  21.  修正を後ろに書くことも出来ます。
  22. INFO_MESSAGE_TEXT
  23. 1 register_prefix('.DPT', '.FT')
  24. 1 def eval_game_system_specific_command(command)
  25. 250 string = command.upcase
  26. 250 table = []
  27. 250 ttype = ""
  28. 250 type = ""
  29. 250 mod = 0
  30. # ダメージペナルティ表
  31. 250 then: 140 else: 110 if /(\w)DPT([+\-\d]*)/i =~ string
  32. 140 ttype = 'ダメージペナルティー'
  33. 140 head = Regexp.last_match(1)
  34. 140 then: 140 else: 0 mod = ArithmeticEvaluator.eval(Regexp.last_match(2)) if Regexp.last_match(2)
  35. 140 type, table = getDamageTypeAndTable(head)
  36. end
  37. # ファンブル表
  38. 250 then: 110 else: 140 if /(\w)FT([+\-\d]*)/i =~ string
  39. 110 ttype = 'ファンブル'
  40. 110 head = Regexp.last_match(1)
  41. 110 then: 110 else: 0 mod = ArithmeticEvaluator.eval(Regexp.last_match(2)) if Regexp.last_match(2)
  42. 110 type, table = getFumbleTypeAndTable(head)
  43. end
  44. 250 then: 0 else: 250 return '1' if type.empty?
  45. 250 dice = @randomizer.roll_index(10) + @randomizer.roll_index(10) + mod
  46. 250 diceOriginalText = dice
  47. 250 then: 0 else: 250 dice = 0 if dice < 0
  48. 250 then: 54 else: 196 dice = 18 if dice > 18
  49. 250 output = "#{type}#{ttype}表[#{diceOriginalText}] > #{table[dice]}"
  50. 250 return output
  51. end
  52. 1 def getDamageTypeAndTable(head)
  53. 160 case head
  54. when: 50 when "S"
  55. 50 type = '射撃'
  56. # 射撃ダメージペナルティー表
  57. 50 table = [
  58. '対象は[死亡]', # 0
  59. '[追加D]4D6/[出血]2D6/[重傷]-30%/[朦朧判定]15', # 1
  60. '[追加D]3D6/[出血]2D6/[重傷]-30%/[朦朧判定]14', # 2
  61. '[追加D]3D6/[出血]2D6/[重傷]-20%/[朦朧判定]14', # 3
  62. '[追加D]3D6/[出血]1D6/[重傷]-20%/[朦朧判定]12', # 4
  63. '[追加D]2D6/[出血]1D6/[重傷]-10%/[朦朧判定]12', # 5
  64. '[追加D]2D6/[軽傷]-20%/[朦朧判定]10', # 6
  65. '[追加D]2D6/[軽傷]-10%/[朦朧判定]10', # 7
  66. '[追加D]2D6/[軽傷]-20%/[朦朧判定]8', # 8
  67. '[追加D]2D6/[軽傷]-20%/[朦朧判定]6', # 9
  68. '[追加D]2D6/[軽傷]-10%/[朦朧判定]4', # 10
  69. '[追加D]1D6/[軽傷]-20%', # 11
  70. '[追加D]1D6/[軽傷]-20%', # 12
  71. '[追加D]1D6/[軽傷]-10%', # 13
  72. '[軽傷]-20%', # 14
  73. '[軽傷]-10%', # 15
  74. '[軽傷]-10%', # 16
  75. '手に持った武器を落とす', # 17
  76. 'ペナルティー無し', # 18
  77. ]
  78. when: 30 when "M"
  79. 30 type = '格闘'
  80. # 格闘ダメージペナルティー表
  81. 30 table = [
  82. '対象は[死亡]', # 0
  83. '[追加D]3D6/[出血]2D6/[重傷]-30%/[朦朧判定]15', # 1
  84. '[追加D]2D6/[出血]2D6/[重傷]-30%/[朦朧判定]14', # 2
  85. '[追加D]2D6/[出血]1D6/[重傷]-20%/[朦朧判定]14', # 3
  86. '[追加D]3D6/[出血]1D6/[重傷]-10%/[朦朧判定]12', # 4
  87. '[追加D]2D6/[軽傷]-20%/[朦朧判定]12', # 5
  88. '[追加D]2D6/[軽傷]-10%/[朦朧判定]12', # 6
  89. '[追加D]2D6/[軽傷]-10%/[朦朧判定]10', # 7
  90. '[追加D]1D6/[軽傷]-20%/[朦朧判定]8', # 8
  91. '[追加D]1D6/[軽傷]-10%/[朦朧判定]8', # 9
  92. '[追加D]1D6/[軽傷]-10%/[朦朧判定]6', # 10
  93. '[軽傷]-20%/[朦朧判定]6', # 11
  94. '[軽傷]-10%/[朦朧判定]6', # 12
  95. '[軽傷]-10%/[朦朧判定]4', # 13
  96. '[軽傷]-20%', # 14
  97. '[軽傷]-10%', # 15
  98. '[軽傷]-10%', # 16
  99. '手に持った武器を落とす', # 17
  100. 'ペナルティー無し', # 18
  101. ]
  102. when: 30 when "V"
  103. 30 type = '車両'
  104. # 車両ダメージペナルティー表
  105. 30 table = [
  106. '[クラッシュ]する。[チェイス]から除外', # 0
  107. '[乗員D]3D6/[操縦性]-20%/[スピン判定]', # 1
  108. '[乗員D]3D6/[操縦性]-20%/[スピン判定]', # 2
  109. '[乗員D]2D6/[操縦性]-10%/[スピン判定]', # 3
  110. '[乗員D]2D6/[操縦性]-10%/[スピン判定]', # 4
  111. '[乗員D]3D6/[スピード]-2/[スピン判定]', # 5
  112. '[乗員D]3D6/[スピード]-2/[スピン判定]', # 6
  113. '[乗員D]2D6/[スピード]-1/[スピン判定]', # 7
  114. '[乗員D]2D6/[スピード]-1/[スピン判定]', # 8
  115. '[乗員D]2D6/[操縦判定]-20%', # 9
  116. '[乗員D]2D6/[操縦判定]-20%', # 10
  117. '[乗員D]1D6/[操縦判定]-10%', # 11
  118. '[乗員D]1D6/[操縦判定]-10%', # 12
  119. '[スピン判定]', # 13
  120. '[スピン判定]', # 14
  121. '乗員に[ショック]-20%', # 15
  122. '乗員に[ショック]-10%', # 16
  123. '乗員に[ショック]-10%', # 17
  124. 'ペナルティー無し', # 18
  125. ]
  126. when: 30 when "G"
  127. 30 type = '汎用'
  128. # 汎用ダメージペナルティー表
  129. 30 table = [
  130. '対象は[死亡]', # 0
  131. '[追加D]4D6/[出血]2D6/[重傷]-30%/[朦朧判定]18', # 1
  132. '[追加D]4D6/[出血]2D6/[重傷]-30%/[朦朧判定]16', # 2
  133. '[追加D]3D6/[出血]2D6/[重傷]-20%/[朦朧判定]14', # 3
  134. '[追加D]3D6/[出血]2D6/[重傷]-20%/[朦朧判定]14', # 4
  135. '[追加D]3D6/[出血]1D6/[重傷]-10%/[朦朧判定]12', # 5
  136. '[追加D]2D6/[出血]1D6/[重傷]-10%/[朦朧判定]12', # 6
  137. '[追加D]2D6/[軽傷]-30%/[朦朧判定]12', # 7
  138. '[追加D]2D6/[軽傷]-30%/[朦朧判定]10', # 8
  139. '[追加D]2D6/[軽傷]-30%/[朦朧判定]8', # 9
  140. '[追加D]2D6/[軽傷]-20%/[朦朧判定]8', # 10
  141. '[追加D]2D6/[軽傷]-20%/[朦朧判定]6', # 11
  142. '[追加D]2D6/[軽傷]-10%/[朦朧判定]6', # 12
  143. '[追加D]1D6/[軽傷]-20%/[朦朧判定]4', # 13
  144. '[追加D]1D6/[軽傷]-20%', # 14
  145. '[追加D]1D6/[軽傷]-10%', # 15
  146. '[軽傷]-20%', # 16
  147. '[軽傷]-10%', # 17
  148. 'ペナルティー無し', # 18
  149. ]
  150. else: 20 else
  151. 20 head = "S" # 間違ったら射撃扱い
  152. 20 type, table = getDamageTypeAndTable(head)
  153. end
  154. 160 return type, table
  155. end
  156. 1 def getFumbleTypeAndTable(head)
  157. 130 case head
  158. when: 50 when "S"
  159. 50 type = '射撃'
  160. # 射撃ファンブル表
  161. 50 table = [
  162. '銃器が暴発、自分に命中。[貫通D]', # 0
  163. '銃器が暴発、自分に命中。[非貫通D]', # 1
  164. '誤射。ランダムに味方に命中。[貫通D]', # 2
  165. '誤射。ランダムに味方に命中。[非貫通D]', # 3
  166. '銃器が完全に故障', # 4
  167. '銃器が完全に故障', # 5
  168. '故障。〈メカニック〉判定に成功するまで射撃不可', # 6
  169. '故障。〈メカニック〉判定に成功するまで射撃不可', # 7
  170. '作動不良。[アイテム使用]を2回行って修理するまで射撃不可', # 8
  171. '作動不良。[アイテム使用]を2回行って修理するまで射撃不可', # 9
  172. '作動不良。[アイテム使用]を行って修理するまで射撃不可', # 10
  173. '作動不良。[アイテム使用]を行って修理するまで射撃不可', # 11
  174. '姿勢を崩す。[不安定]', # 12
  175. '姿勢を崩す。[不安定]', # 13
  176. '姿勢を崩す。[ショック]-20%', # 14
  177. '姿勢を崩す。[ショック]-20%', # 15
  178. '姿勢を崩す。[ショック]-10%', # 16
  179. '姿勢を崩す。[ショック]-10%', # 17
  180. 'ペナルティー無し', # 18
  181. ]
  182. when: 30 when "M"
  183. 30 type = '格闘'
  184. # 格闘ファンブル表
  185. 30 table = [
  186. '避けられて[転倒]、[朦朧]状態', # 0
  187. 'ランダムに[至近距離]の味方(居なければ自分)に命中。[貫通D]', # 1
  188. 'ランダムに[至近距離]の味方(居なければ自分)に命中。[貫通D]', # 2
  189. '武器が完全に壊れる', # 3
  190. '武器がガタつく。〈手先〉判定に成功するまで使用不可', # 4
  191. '武器がガタつく。〈手先〉判定に成功するまで使用不可', # 5
  192. '無理な姿勢で筋を伸ばす。[軽傷]-30%', # 6
  193. '無理な姿勢で筋を伸ばす。[軽傷]-30%', # 7
  194. '無理な姿勢で筋を伸ばす。[軽傷]-20%', # 8
  195. '無理な姿勢で筋を伸ばす。[軽傷]-20%', # 9
  196. '無理な姿勢で筋を伸ばす。[軽傷]-10%', # 10
  197. '無理な姿勢で筋を伸ばす。[軽傷]-10%', # 11
  198. '姿勢を崩す。[不安定]', # 12
  199. '姿勢を崩す。[不安定]', # 13
  200. '姿勢を崩す。[ショック]-20%', # 14
  201. '姿勢を崩す。[ショック]-20%', # 15
  202. '姿勢を崩す。[ショック]-10%', # 16
  203. '姿勢を崩す。[ショック]-10%', # 17
  204. 'ペナルティー無し', # 18
  205. ]
  206. when: 30 when "T"
  207. 30 type = '投擲'
  208. # 投擲ファンブル表
  209. 30 table = [
  210. '[転倒]、[朦朧]状態', # 0
  211. '自分に命中。[貫通D]', # 1
  212. '自分に命中。[非貫通D]', # 2
  213. 'ランダムに味方(居なければ自分)に命中。[非貫通D]', # 3
  214. 'ランダムに味方(居なければ自分)に命中。[非貫通D]', # 4
  215. '武器が完全に壊れる', # 5
  216. '武器が完全に壊れる', # 6
  217. '腰を痛める。[軽傷]-30%', # 7
  218. '肩を痛める。[軽傷]-20%', # 8
  219. '肩を痛める。[軽傷]-20%', # 9
  220. '肘に違和感。[軽傷]-10%', # 10
  221. '肘に違和感。[軽傷]-10%', # 11
  222. '姿勢を崩す。[不安定]', # 12
  223. '姿勢を崩す。[不安定]', # 13
  224. '姿勢を崩す。[ショック]-20%', # 14
  225. '姿勢を崩す。[ショック]-20%', # 15
  226. '姿勢を崩す。[ショック]-10%', # 16
  227. '姿勢を崩す。[ショック]-10%', # 17
  228. 'ペナルティー無し', # 18
  229. ]
  230. else: 20 else
  231. 20 head = "S" # 間違ったら射撃扱い
  232. 20 type, table = getFumbleTypeAndTable(head)
  233. end
  234. 130 return type, table
  235. end
  236. end
  237. end
  238. end

lib/bcdice/game_system/GurpsFW.rb

61.58% lines covered

42.77% branches covered

341 relevant lines. 210 lines covered and 131 lines missed.
166 total branches, 71 branches covered and 95 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class GurpsFW < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'GurpsFW'
  7. # ゲームシステム名
  8. 1 NAME = 'ガープスフィルトウィズ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'かあふすふいるとういす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. --GURPS汎用コマンド----------
  14. ・判定においてクリティカル・ファンブルの自動判別、成功度の自動計算。(3d6<=目標値)
  15. ・祝福等のダイス目にかかる修正は「3d6-1<=目標値」といった記述で計算されます。
  16. (ダイス目の修正値はクリティカル・ファンブルに影響を与えません。)
  17. ・クリティカル値・ファンブル値への修正については現在対応していません。
  18. ・クリティカル表 (CRT)
  19. ・頭部打撃クリティカル表 (HCRT)
  20. ・ファンブル表 (FMB)
  21. ・呪文ファンブル表 (MFMB)
  22. ・命中部位表 (HIT)
  23. ・恐怖表 (FEAR+n)
  24.  nには恐怖判定の失敗度を入れてください。
  25. ・反応判定表 (REACT, REACT±n)
  26.  nには反応修正を入れてください。
  27. ・D66ダイスあり
  28. --GURPS-FW専用コマンド----------
  29. ・ドロップ判定(DROP)/ネームドドロップ判定(DROPN)
  30. ・ドロップ判定に修正が付く場合は末尾に+xを記述(xは修正値)。(DROP+x、DROPN+x)
  31. ・必殺技表(HST)/驚異的必殺技表(KHST)
  32. ・ホムンクルスの【必殺技!】/【驚異的必殺技!】用コマンド。
  33. ・ナンバーワンくじ/ノーマル(LOTN)/プレミアム(LOTP)
  34. --夢幻の迷宮(ver.2013/11/07)----------
  35. ・コマンド中のdには難易度を入れてください。(初級:E 中級:N 上級:H 悪夢:L)
  36. ・コマンド中のaには地形を入れてください。
  37. (1:洞窟 2:遺跡 3:断崖 4:水辺 5:森林 6:墓地)
  38. ・ランダムイベント(RANDd)/地形固定(RANDda)
  39. ・ランダムエンカウント(RENCd)/地形固定(RENCda)
  40. ・トラップリスト(TRAPd)
  41. ・報酬財宝テーブル(xに到達深度を記述)。 (TRSdx)
  42. ・財宝テーブルの段階が変動する場合、末尾に±yを記述(yは変動段階)。(TRSdx±y)
  43. [例:TRSE5-1、TRSH36+2]
  44. ・地形決定表(AREA)
  45. ・迷宮追加オプション表(RANDOP)
  46. INFO_MESSAGE_TEXT
  47. 1 register_prefix(
  48. 'CRT',
  49. 'HCRT',
  50. 'FMB',
  51. 'MFMB',
  52. 'HIT',
  53. 'FEAR',
  54. 'REACT',
  55. 'TRAP[ENHL]',
  56. 'TRS[ENHL]',
  57. 'RAND[ENHL]',
  58. 'RENC[ENHL]',
  59. 'AREA',
  60. 'DROPN?',
  61. 'HST',
  62. 'KHST',
  63. 'RANDOP',
  64. 'LOT[NP]'
  65. )
  66. 1 def initialize(command)
  67. 36 super(command)
  68. 36 @d66_sort_type = D66SortType::NO_SORT
  69. end
  70. 1 def result_nd6(total, dice_total, dice_list, cmp_op, target)
  71. 16 then: 1 else: 15 return Result.nothing if target == '?'
  72. 15 else: 15 then: 0 return nil unless dice_list.size == 3 && cmp_op == :<=
  73. 15 success = target - total # 成功度
  74. 15 crt_string = Result.critical("クリティカル(成功度:#{success})")
  75. 15 fmb_string = Result.fumble("ファンブル(失敗度:#{success})")
  76. 15 fail_string = Result.failure("自動失敗(失敗度:#{success})")
  77. # クリティカル
  78. 15 then: 1 if (dice_total <= 6) && (target >= 16)
  79. 1 else: 14 return crt_string
  80. 14 then: 1 elsif (dice_total <= 5) && (target >= 15)
  81. 1 else: 13 return crt_string
  82. 13 then: 2 else: 11 elsif dice_total <= 4
  83. 2 return crt_string
  84. end
  85. # ファンブル
  86. 11 then: 1 if (target - dice_total) <= -10
  87. 1 else: 10 return fmb_string
  88. 10 then: 2 elsif (dice_total >= 17) && (target <= 15)
  89. 2 else: 8 return fmb_string
  90. 8 then: 0 elsif dice_total >= 18
  91. else: 8 return fmb_string
  92. 8 then: 2 else: 6 elsif dice_total >= 17
  93. 2 return fail_string
  94. end
  95. 6 then: 3 if total <= target
  96. 3 return Result.success("成功(成功度:#{success})")
  97. else: 3 else
  98. 3 return Result.failure("失敗(失敗度:#{success})")
  99. end
  100. end
  101. 1 def eval_game_system_specific_command(string)
  102. 20 tableName = ""
  103. 20 result = ""
  104. 20 number = 0
  105. 20 case string
  106. when: 1 when "CRT"
  107. 1 tableName = "クリティカル表"
  108. 1 table = [
  109. '体を狙っていたら、相手は気絶(回復は30分後に生命力判定)。他はダメージ3倍。',
  110. '相手の防御点を無視。',
  111. 'ダメージ3倍。',
  112. 'ダメージ2倍。',
  113. '相手は生命力判定を行い、失敗すると朦朧状態となる。',
  114. '四肢を狙っていたら、6ターンそこが使えなくなる。通常ダメージ。',
  115. '通常ダメージ。',
  116. '通常ダメージ。',
  117. '通常ダメージ。',
  118. '四肢を狙っていたら、6ターンそこが使えなくなる。通常ダメージ。',
  119. '相手の防御点を無視。',
  120. '四肢を狙っていたら、そこが使えなくなる(通常ダメージ)。他は2倍ダメージ。',
  121. '相手は武器を落とす。通常ダメージ。',
  122. 'ダメージ2倍。',
  123. 'ダメージ3倍。',
  124. '体を狙っていたら、相手は気絶(回復は30分後に生命力判定)。他はダメージ3倍。',
  125. ]
  126. 1 result, number = get_table_by_nD6(table, 3)
  127. when: 0 when "HCRT"
  128. tableName = "頭部打撃クリティカル表"
  129. table = [
  130. '敵は即死する',
  131. '敵は意識を失う。30分ごとに生命力判定をして、成功すると意識を回復する。',
  132. '敵は意識を失う。30分ごとに生命力判定をして、成功すると意識を回復する。',
  133. '敵は両目を負傷する。朦朧状態になる。目が見えないので、敏捷力-10。',
  134. '敵は片目を負傷する。朦朧状態になる。敏捷力-2。',
  135. '敵はバランスを失う。次のターンまで、防御しかできない。',
  136. '通常ダメージのみ。',
  137. '通常ダメージのみ。',
  138. '通常ダメージのみ。',
  139. '「叩き」攻撃なら、敵は24時間のあいだ耳が聞こえなくなる。「切り」「刺し」なら、1点しかダメージを与えられないが、傷跡が残る。',
  140. '「叩き」攻撃なら、敵は耳が聞こえなくなる。「切り」「刺し」なら、2点しかダメージを与えられないが、傷跡が残る。',
  141. '敵は逃げ腰になって武器を落とす(両手に武器を持っていたらランダムに決定)。',
  142. '敵は通常のダメージを受け、朦朧状態になる。',
  143. '敵は通常のダメージを受け、朦朧状態になる。',
  144. '敵は通常のダメージを受け、朦朧状態になる。',
  145. '敵は通常のダメージを受け、朦朧状態になる。',
  146. ]
  147. result, number = get_table_by_nD6(table, 3)
  148. when: 1 when "FMB"
  149. 1 tableName = "ファンブル表"
  150. 1 table = [
  151. '武器が壊れる。ただし、メイスなど固い"叩き"武器は壊れない(ふりなおし)。',
  152. '武器が壊れる。ただし、フレイルなど固い"叩き"武器は壊れない(ふりなおし)。',
  153. '自分の腕か足に命中(通常ダメージ)。ただし"刺し"武器や射撃ならふりなおし。',
  154. '自分の腕か足に命中(半分ダメージ)。ただし"刺し"武器や射撃ならふりなおし。',
  155. 'バランスを失い、次ターンは行動不可。次ターンの行動の番まで、能動防御-2。',
  156. '使った武器が非準備状態になる。1ターンよぶんに準備行動を行わないと、準備状態にならない。',
  157. '武器を落とす。',
  158. '武器を落とす。',
  159. '武器を落とす。',
  160. '使った武器が非準備状態になる。1ターンよぶんに準備行動を行わないと、準備状態にならない。',
  161. 'バランスを失い、次ターンは行動不可。次ターンの行動の番まで、能動防御-2。',
  162. '前か後ろ(ランダム)に武器が1メートル飛んでいく。その場にいるキャラクターは敏捷力判定を行い、失敗するとダメージ(通常の半分)を受ける。ただし、"刺し"武器や弓矢はその場に落ちるだけ。',
  163. '利き腕をくじいてしまう。30分間、攻撃にも防御にも使えない。',
  164. '足をすべらせ、その場に倒れる。',
  165. '武器が壊れる。ただし、モールなど固い"叩き"武器は壊れない(ふりなおし)。',
  166. '武器が壊れる。ただし、金属バットなど固い"叩き"武器は壊れない(ふりなおし)。',
  167. ]
  168. 1 result, number = get_table_by_nD6(table, 3)
  169. when: 1 when "MFMB"
  170. 1 tableName = "呪文ファンブル表"
  171. 1 table = [
  172. '呪文が完全に失敗する。術者は1D点のダメージを受ける。',
  173. '呪文が術者にかかる。',
  174. '呪文が術者の仲間にかかる(対象はランダムに決定)。',
  175. '呪文が近くの敵にかかる(対象はランダムに決定)。',
  176. '哀れな物音があがり、硫黄のひどい匂いが立ち込める。',
  177. '呪文が目標以外のもの(仲間、敵、品物)にかかる。対象はランダムに決定するか、おもしろくなるようにGMが決定する。',
  178. '呪文が完全に失敗する。術者は1点のダメージを受ける。',
  179. '呪文が完全に失敗する。術者は朦朧状態になる(立ち直るには知力判定を行う)。',
  180. '大きな物音があがり、色とりどりの閃光が走る。',
  181. '見せ掛けの効果があらわれるが、弱くてとても役に立たない。',
  182. '意図した効果と逆の効果があらわれる。',
  183. '違った目標に、意図した効果とは逆の効果があらわれる(対象はランダムに決定)。',
  184. '何も起こらないが、術者は一時的にその呪文を忘れてしまう。思い出すまで、1週間ごとに知力判定を行う。',
  185. '呪文がかかったように思えるが、役に立たないただの見せかけだけ。',
  186. '呪文が完全に失敗し、術者の右腕が損なわれる。回復に1週間を要する。',
  187. '呪文が完全に失敗する。GMから見て、術者や呪文が純粋で善良なものでなければ、悪魔(第3版文庫版P.384参照)があらわれ、術者を攻撃する。',
  188. ]
  189. 1 result, number = get_table_by_nD6(table, 3)
  190. when: 0 when "HIT"
  191. tableName = "命中部位表"
  192. table = [
  193. '脳',
  194. '脳',
  195. '頭',
  196. '遠い腕',
  197. '手首(左右ランダム)',
  198. '近い腕',
  199. '胴体',
  200. '胴体',
  201. '胴体',
  202. '遠い足',
  203. '近い足',
  204. '近い足',
  205. '足首(左右ランダム)',
  206. '足首(左右ランダム)',
  207. '重要機関(胴体の)',
  208. '武器',
  209. ]
  210. result, number = get_table_by_nD6(table, 3)
  211. when: 2 when /FEAR((\+)?\d+)?/
  212. 2 modify = Regexp.last_match(1).to_i
  213. 2 tableName = "恐怖表"
  214. 2 table = [
  215. '1ターン朦朧状態。2ターン目に自動回復。',
  216. '1ターン朦朧状態。2ターン目に自動回復。',
  217. '1ターン朦朧状態。以後、毎ターン不利な修正を無視した意志判定を行い、成功すると回復。',
  218. '1ターン朦朧状態。以後、毎ターン不利な修正を無視した意志判定を行い、成功すると回復。',
  219. '1ターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  220. '1ターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  221. '1Dターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  222. '2Dターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  223. '思考不能。15ターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  224. '新たな癖をひとつ植え付けられる。',
  225. '1D点疲労。さらに1Dターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  226. '1D点疲労。さらに1Dターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  227. '新たな癖をひとつ獲得。さらに1Dターン朦朧状態。以後、毎ターン通常の意志判定を行い、成功すると回復。',
  228. '1D分間意識を失う。以後、1分ごとに生命力判定を行い、成功すると回復。',
  229. '生命力判定を行い、失敗すると1点の負傷を受ける。さらに1D分間意識を失う。以後、1分ごとに生命力判定を行い、成功すると回復。',
  230. '1点負傷。2D分間意識を失う。以後、1分ごとに生命力判定を行い、成功すると回復。',
  231. '卒倒。4D分間意識不明。1D点疲労。',
  232. 'パニック。1D分間のあいだ、叫びながら走り回ったり、座り込んで泣きわめいたりする。以後、1分ごとに知力判定(修正なし)を行い、成功すると回復。',
  233. '-10CPの妄想を植え付けられる。',
  234. '-10CPの軽い恐怖症を植え付けられる。',
  235. '肉体的な変化。髪が真白になったり、老化したりする。-15CPぶんの肉体的特徴に等しい。',
  236. 'その恐怖に関連する軽い恐怖症を持っているならそれが強い恐怖症(CP2倍)になる。そうでなければ、-10CPぶんの精神的特徴を植え付けられる。',
  237. '-10CPの妄想を植え付けられる。生命力判定を行い、失敗すると1点の負傷を受ける。さらに1D分間意識を失う。以後、1分ごとに生命力判定を行い、成功すると回復。',
  238. '-10CPの軽い恐怖症を植え付けられる。生命力判定を行い、失敗すると1点の負傷を受ける。さらに1D分間意識を失う。以後、1分ごとに生命力判定を行い、成功すると回復。',
  239. '浅い昏睡状態。30分ごとに生命力判定を行い、成功すると目覚める。目覚めてから6時間はあらゆる判定に-2の修正。',
  240. '昏睡状態。1時間ごとに生命力判定を行い、成功すると目覚める。目覚めてから6時間はあらゆる判定に-2の修正。',
  241. '硬直。1D日のあいだ身動きしない。その時点で生命力判定を行い、成功すると動けるようになる。失敗するとさらに1D日硬直。その間、適切な医学的処置を受けていないかぎり、初日に1点、2日目に2点、3日目に3点と生命力を失っていく。動けるようになってからも、硬直していたのと同じ日数だけ、あらゆる判定に-2の修正。',
  242. '痙攣。1D分間地面に倒れて痙攣する。2D点疲労。また、生命力判定に失敗すると1D点負傷。これがファンブルなら生命力1点を永遠に失う。',
  243. '発作。軽い心臓発作を起こし、地面に倒れる。2D点負傷。',
  244. '大パニック。キャラクターは支離滅裂な行動に出る。GMが3Dを振り、目が大きければ大きいほど馬鹿げた行動を行う。その行動が終わったら知力判定を行い、成功すると我に返る。失敗すると新たな馬鹿げた行動をとる。',
  245. '強い妄想(-15CP)を植え付けられる。',
  246. '強い恐怖症、ないし-15CPぶんの精神的特徴を植え付けられる。',
  247. '激しい肉体的変化。髪が真白になったり、老化したりする。-20CPぶんの肉体的特徴に等しい。',
  248. '激しい肉体的変化。髪が真白になったり、老化したりする。-30CPぶんの肉体的特徴に等しい。',
  249. '昏睡状態。1時間ごとに生命力判定を行い、成功すると目覚める。目覚めてから6時間はあらゆる判定に-2の修正。さらに強い妄想(-15CP)を植え付けられる。',
  250. '昏睡状態。1時間ごとに生命力判定を行い、成功すると目覚める。目覚めてから6時間はあらゆる判定に-2の修正。さらに強い恐怖症、ないし-30CPぶんの精神的特徴を植え付けられる。',
  251. '昏睡状態。1時間ごとに生命力判定を行い、成功すると目覚める。目覚めてから6時間はあらゆる判定に-2の修正。さらに強い恐怖症、ないし-30CPぶんの精神的特徴を植え付けられる。知力が1点永遠に低下する。あわせて精神系の技能、呪文、超能力のレベルも低下する。',
  252. ]
  253. 2 dice = @randomizer.roll_sum(3, 6)
  254. 2 number = dice + modify
  255. 2 then: 0 if number > 40
  256. num = 36
  257. else: 2 else
  258. 2 num = number - 4
  259. end
  260. 2 result = table[num]
  261. when: 3 when /REACT((\+|-)?\d*)/
  262. 3 modify = Regexp.last_match(1).to_i
  263. 3 tableName = "反応表"
  264. 3 dice = @randomizer.roll_sum(3, 6)
  265. 3 number = dice + modify
  266. 3 then: 0 if number < 1
  267. else: 3 result = "最悪"
  268. 3 then: 0 elsif number < 4
  269. else: 3 result = "とても悪い"
  270. 3 then: 0 elsif number < 7
  271. else: 3 result = "悪い"
  272. 3 then: 0 elsif number < 10
  273. else: 3 result = "良くない"
  274. 3 then: 0 elsif number < 13
  275. else: 3 result = "中立"
  276. 3 then: 0 elsif number < 16
  277. else: 3 result = "良い"
  278. 3 then: 2 elsif number < 19
  279. 2 result = "とても良い"
  280. else: 1 else
  281. 1 result = "最高"
  282. end
  283. when: 1 when /TRAP(\w)/
  284. 1 tableName = "トラップリスト"
  285. 1 diff = Regexp.last_match(1)
  286. 1 dif, table = getTrapTable(diff)
  287. 1 then: 0 else: 1 if table.nil?
  288. return ""
  289. end
  290. 1 result, number = get_table_by_nD6(table, 3)
  291. 1 result = "#{dif}:#{result}"
  292. when: 1 when /TRS(E|N|H|L)(\d+)((\+|-)?\d*)/
  293. 1 tableName = "財宝テーブル"
  294. 1 diff = Regexp.last_match(1)
  295. 1 depth = Regexp.last_match(2).to_i
  296. 1 num = depth / 10
  297. 1 then: 0 else: 1 if num >= 6
  298. num = 5
  299. end
  300. 1 else: 0 case diff
  301. when: 1 when "N"
  302. 1 num += 1
  303. when: 0 when "H"
  304. num += 2
  305. when: 0 when "L"
  306. num += 3
  307. end
  308. 1 else: 1 then: 0 unless Regexp.last_match(4).nil?
  309. num += Regexp.last_match(3).to_i
  310. end
  311. 1 table = getTresureTable(num)
  312. 1 then: 0 else: 1 if table.nil?
  313. return ""
  314. end
  315. 1 result, number = get_table_by_1d6(table)
  316. when: 1 when /RAND(E|N|H|L)(\d)?/
  317. 1 tableName = "ランダムイベント表"
  318. 1 diff = Regexp.last_match(1)
  319. 1 then: 0 if !Regexp.last_match(2).nil?
  320. dice1 = Regexp.last_match(2).to_i
  321. else: 1 else
  322. 1 dice1 = @randomizer.roll_once(6)
  323. end
  324. 1 dice2 = @randomizer.roll_once(6)
  325. 1 area, dif, table = getRandomEvent(dice1, dice2, diff)
  326. 1 result, dice3 = get_table_by_1d6(table)
  327. 1 number = "#{dice1}#{dice2}#{dice3}"
  328. 1 result = "#{area}(#{dif}):#{result}"
  329. when: 1 when /RENC(E|N|H|L)(\d)?/
  330. 1 tableName = "ランダムエンカウント表"
  331. 1 diff = Regexp.last_match(1)
  332. 1 then: 0 if !Regexp.last_match(2).nil?
  333. dice1 = Regexp.last_match(2).to_i
  334. else: 1 else
  335. 1 dice1 = @randomizer.roll_once(6)
  336. end
  337. 1 dice2 = 4
  338. 1 area, dif, table = getRandomEvent(dice1, dice2, diff)
  339. 1 result, dice3 = get_table_by_1d6(table)
  340. 1 number = "#{dice1}#{dice2}#{dice3}"
  341. 1 result = "#{area}(#{dif}):#{result}"
  342. when: 1 when "AREA"
  343. 1 tableName = "地形決定表"
  344. 1 table = [
  345. '洞窟
  346. 「ん、暗くて先が見えないって?そりゃこのフィルトウィズのことかい?」
  347. 姿を様々に変える洞窟。ケイヴウォーカーがいれば有利に探索可能。非常に暗く「暗視」がなければ満足に進むことはできないだろう。
  348. ☆深度判定:体力判定(「暗視」があれば深度判定に+3のボーナスを受ける)
  349. ☆屋内(飛行不可)
  350. ☆薄暗い(ストームコーザー「鳥目」を適用)',
  351. '遺跡
  352. 「どんな仕掛けにだって意味はある。人が作ったものだからな」
  353. 人為的に作られた様々な建造物の内部。
  354. 様々な恐ろしい仕掛けが行く手を阻む。
  355. ☆深度判定:<探索>
  356. ☆屋内(飛行不可)',
  357. '断崖
  358. 「うーん、とっても気持ちのいい風ね。ん?何を震えてるの?」
  359. 一歩踏み外せば奈落の底。過酷な自然の要塞。
  360. ストームコーザーなどの飛行可能な仲間がいると心強いだろう。
  361. ☆深度判定:<軽業>
  362. ☆屋外',
  363. '水辺
  364. 「人間とは何かと不便なことが多い種族ですな」
  365. 川、湖などを泳いだりして進んでいくダンジョン。
  366. リザードやワイズマンがその力を発揮するだろう。
  367. ☆深度判定:<水泳>
  368. (水泳に「自動的に成功」するキャラクターは敏捷力+4で判定可能。
  369. 《水泳》のかかっているキャラクターがいた場合も同様。
  370. 【ミズグモ】があれば敏捷力+2で深度判定可能)
  371. ☆屋外 ',
  372. '森林
  373. 「ここが危険だと思う?それはアナタがこの森では『異質』だからよ」
  374. 鬱蒼とした森林は、人間にはとても過酷な環境となっている。
  375. フラウなどの自然と共に生きる者の力が助けになるだろう。
  376. ☆深度判定:<生存>
  377. ☆屋外',
  378. '墓地
  379. 「客人とは珍しい・・・『死者の王』に出会わぬよう、ゆめゆめご注意を・・・」
  380. 死者どもの彷徨う、暗く冷たい墓地。
  381. ローブをかぶった得体の知れない墓守を<追跡>して脱出せよ。
  382. ☆深度判定:<追跡>
  383. ☆屋外
  384. ☆薄暗い(ストームコーザー「鳥目」を適用)',
  385. ]
  386. 1 result, number = get_table_by_1d6(table)
  387. when: 2 when /DROP(N)?((\+)?(\d))?/
  388. 2 tableName = "ドロップ判定"
  389. 2 mode = "S"
  390. 2 modify = 0
  391. 2 else: 1 then: 1 unless Regexp.last_match(1).nil?
  392. 1 mode = Regexp.last_match(1)
  393. end
  394. 2 else: 2 then: 0 unless Regexp.last_match(4).nil?
  395. modify = Regexp.last_match(4).to_i
  396. end
  397. 2 dice = @randomizer.roll_sum(3, 6)
  398. 2 number = dice - modify
  399. 2 then: 1 if number <= 3
  400. 1 result = "レアアイテム1"
  401. else: 1
  402. 1 then: 0 elsif (number <= 4) && (mode == "N")
  403. result = "レアアイテム2"
  404. else: 1
  405. 1 then: 0 elsif number < 7
  406. then: 0 if mode == "N"
  407. result = "CL×200GP"
  408. else: 0 else
  409. result = "CL×100GP"
  410. end
  411. else: 1 else
  412. 1 then: 0 if mode == "N"
  413. result = "CL×20GP"
  414. else: 1 else
  415. 1 result = "CL×10GP"
  416. end
  417. end
  418. when: 1 when "HST"
  419. 1 tableName = "必殺技表"
  420. 1 table = [
  421. '命中判定に[1,1,1]でクリティカル(クリティカル表も参照)。',
  422. '命中判定に+20のボーナス。',
  423. 'ダメージを与えると「生命力-2」で気絶判定。',
  424. 'ダメージを与えると「敏捷力-4」で転倒判定。',
  425. '致傷力+2D。',
  426. '命中判定に[6,6,6]でファンブル(ファンブル表も参照)。',
  427. ]
  428. 1 result, number = get_table_by_1d6(table)
  429. when: 1 when "KHST"
  430. 1 tableName = "驚異的必殺技表"
  431. 1 table = [
  432. '命中判定に[1,1,1]でクリティカル。クリティカル表は参照せず、相手は即死。「分類:ネームド」「分類:魔将」に対しては最大HPの半分のダメージを与える。',
  433. '命中判定に[1,1,1]でクリティカル。クリティカル表は参照せず、致傷力3倍。',
  434. '命中判定に[1,1,1]でクリティカル。クリティカル表は参照せず、致傷力2倍。',
  435. '命中判定に[1,1,1]でクリティカル(クリティカル表も参照)。',
  436. '命中判定に+40のボーナス。',
  437. '致傷力+4D(火炎特性)。',
  438. '致傷力+3D(雷撃特性)。',
  439. '与えたダメージに等しいHPを回復する。回避に-3のペナルティを与える。',
  440. '1点でもダメージを与えた場合、対象を転倒状態にする。回避に-3のペナルティを与える。',
  441. '致傷力+3D。',
  442. '致傷力+4D(冷気特性)。',
  443. '1点でもダメージを与えた場合、-6のペナルティで気絶判定。',
  444. '致傷力+4D。防護点無視。',
  445. '致傷力+6D。回避に-3のペナルティを与える。',
  446. '命中判定に[6,6,5]でファンブル(ファンブル表も参照)。目標値が16以上だった場合は自動失敗。',
  447. '命中判定に[6,6,6]でファンブル(ファンブル表も参照)。',
  448. ]
  449. 1 result, number = get_table_by_nD6(table, 3)
  450. when: 1 when "RANDOP"
  451. 1 tableName = "迷宮追加オプション表"
  452. 1 table = [
  453. '「宝物の迷宮」
  454. 財宝決定の際、1段階深度の高い財宝テーブルを使用する。',
  455. '「密林の迷宮」 初期深度+10
  456. 分類が「魔獣」「獣人」「霊獣」のモンスターは全ての判定に+2のボーナスを得る。',
  457. '「カラクリ技師の迷宮」
  458. 分類「ギア」のモンスターは全ての判定に+2のボーナスを得る。
  459. クリア時に獲得できるAPが2倍になる。',
  460. '「フラウの舞踏会」
  461. フラウが登場するランダムイベントが発生した際、
  462. 「この迷宮を制覇して、私達が舞踏会を開けるようにしてね」とお願いされ、
  463. 迷宮クリア時の獲得CPに+1のボーナスを得る。',
  464. '「アズマ風の迷宮」 初期深度+10
  465. 風流なアズマ風の迷宮。
  466. アシガルファイター(CL4)、アンブッシュマン(CL5)、カラクリフラウ(CL6)、
  467. ヤコ(CL6)、ヤシャ(CL10)、ヒトキリ(CL33)、シャドウストーカー(CL35)、
  468. アシュラ(CL48)、コンゴウ(CL60)、カラクリヒメショーグン(CL75)が行う、
  469. 全ての判定に+2のボーナスを得る。',
  470. '「枯れた泉の迷宮」 初期深度+5
  471. 回復の泉が全て枯れており、回復効果を得ることができない。毒の泉はそのまま存在する。',
  472. '「天空への道」 初期深度+15
  473. 上へ上へと果てしなく昇っていく迷宮。空気が薄くなって疲労しやすくなる。
  474. 技などによるFPの最終的な消費と、FPに受ける最終的なダメージが2倍になる。',
  475. '「灼熱焦土の塔」 初期深度+10
  476. とてつもなく熱く、気温が50度以上の塔。
  477. 「特性:火炎」の攻撃でPCが受ける最終的なダメージが2倍になる。',
  478. '「永久凍土の塔」 初期深度+10
  479. とてつもなく寒く、気温が氷点下の塔。
  480. 「特性:冷気」の攻撃でPCが受ける最終的なダメージが2倍になる。
  481. リザードやワイズマンなどの寒さに弱いキャラクターは動きが鈍り、あらゆる判定に-2のペナルティを受ける。',
  482. '「盗賊王の迷宮」 初期深度+10
  483. <罠><鍵開け>に+3のペナルティを受ける。',
  484. '「ミミック狂暴化」
  485. 「全地形2-5」のミミックを見破る<罠>の判定に-3のペナルティを受け、
  486. ミミックの致傷力も2倍になる。ミミックから獲得できるGPが3倍になる。',
  487. '「トレジャーイーター狂暴化」 初期深度+10
  488. 「全地形2-6」のトレジャーイーターを見破る<罠>の判定に-5のペナルティを受ける。',
  489. '「暗闇の迷宮」 初期深度+5
  490. 「暗視」がなければ視覚判定に-5のペナルティを受ける。
  491. ストームコーザーはペナルティが2倍。',
  492. '「騒音の迷宮」 初期深度+5
  493. 「音量自動補正装置」がなければ聴覚判定に-5のペナルティを受ける。
  494. シルヴァテイルはペナルティが2倍。',
  495. '「未知の怪物の迷宮」 初期深度+10
  496. モンスターのデータが判明させられなくなる。
  497. モンスター名は全て「謎の影」となる',
  498. '「氾濫中の迷宮」 初期深度+10
  499. <水泳>に-5のペナルティを受ける。',
  500. '「間抜けの迷宮」 初期深度+15
  501. あらゆる知力を基準とした判定(精神系技能含む)に-2のペナルティを受ける。',
  502. '「瘴気の迷宮」 初期深度+15
  503. あらゆる生命力判定に-4のペナルティを受ける。',
  504. '「加速する迷宮」
  505. 1ラウンドで1日が経過する迷宮。技のCTやフラウの水分補給に影響する。
  506. 「CT:1日」までの技も次ターンで使用可能になっている。',
  507. '「停滞する迷宮」
  508. 敵味方双方が、「CT:次ターン」の技を使用すると最終イベントまで再使用不可。
  509. また、「次ターンまで」有効な技は最終イベントまでずっと適用される。',
  510. '「猛毒の迷宮」 初期深度+20
  511. 最大HP、MP、FPに-5のペナルティを受ける。最低1点は残る。
  512. 中級:-10 上級:-15 悪夢:-20',
  513. '「死の迷宮」 初期深度+25
  514. 「保険」の効果が適用されない迷宮。',
  515. '「幸運の迷宮」
  516. PC全員のフォーチュン最大値+1。',
  517. '「不運の迷宮」 初期深度+10
  518. PC全員のフォーチュン最大値が半減する。',
  519. '「レアメタルの迷宮」
  520. 非常にレアなモンスター「レアメタルキャンディー」「レアメタルクラウン」が生息している迷宮。
  521. キャンディークラウン(CL40)、ゴールデンクラウン(CL177)から
  522. 獲得できるAPが5倍になる。ただし、この2体の防護点は10になる。',
  523. '「魔力の泉」
  524. PCとモンスターの双方が、MPを減少させずに魔法を使用できるようになる。
  525. 最大MPの足りていない魔法は使用できない。',
  526. '「青色の迷宮」 初期深度+10
  527. PCは全員「内気3」の特徴を得る。
  528. 迷宮内で他のNPCに出会った際のイベントは全て無視する。',
  529. '「赤色の迷宮」 初期深度+10
  530. PCは全員「直情」「自信過剰」の特徴を得る。「撤退」はできなくなる。',
  531. '「ピンクの迷宮」
  532. PCは全員「好色」「平和愛好/専守防衛」の特徴を得る。「分類:魔族」とのエンカウントは無視する。',
  533. '「ハズレの迷宮」
  534. 財宝決定の際、1段階深度の低い財宝テーブルを使用する。',
  535. '「ラダマンティスの迷宮」 初期深度+20
  536. 「分類:岩石」のモンスターは全ての判定に+3のボーナスを得る。
  537. また、「遺跡6-6」のイベントの致傷力が2倍になる。',
  538. '「グレイヴディガーの迷宮」 初期深度+20
  539. 「分類:アンデッド」のモンスターは全ての判定に+3のボーナスを得る。
  540. また、「墓場」の深度判定に-5のペナルティを受ける。',
  541. '「ハイペリオンの迷宮」 初期深度+20
  542. 全てのモンスターがターンの最初にHPを5点ずつ回復する。
  543. 中級:10点 上級:20点 悪夢:30点。',
  544. '「ムスペルニブルの迷宮」 初期深度+20
  545. 「特性:火炎」「特性:冷気」の攻撃で、PCが受ける最終的なダメージが2倍になる。',
  546. '「 の迷宮」
  547. 何も起きない。第五魔将の封印が解除されている場合のみ、フォーチュン最大値+5。',
  548. '「バロールの迷宮」 初期深度+20
  549. 「分類:ギア」のモンスターは全ての判定とあらゆる攻撃の致傷力に+3のボーナスを得る。',
  550. ]
  551. 1 result, number = get_table_by_d66(table)
  552. when: 2 when /LOT(N|P)/
  553. 2 type = Regexp.last_match(1)
  554. 2 then: 1 if type == "P"
  555. 1 tableName = "ナンバーワンプレミアムくじ"
  556. else: 1 else
  557. 1 tableName = "ナンバーワンノーマルくじ"
  558. end
  559. 2 result = getLotResult(type)
  560. 2 return "#{tableName}:#{result}"
  561. else: 0 else
  562. return nil
  563. end
  564. 18 text = "#{tableName}(#{number}):#{result}"
  565. 18 return text
  566. end
  567. # ノーマルくじ表1
  568. 1 def normal1
  569. table = [
  570. 1 'イレブンチキン',
  571. 'イレブンチキン',
  572. 'イレブンチキン',
  573. 1 lambda { return normal2.to_s },
  574. lambda { return normal2.to_s },
  575. lambda { return normal3.to_s },
  576. ]
  577. 1 result, = get_table_by_1d6(table)
  578. 1 return result
  579. end
  580. # ノーマルくじ表2
  581. 1 def normal2
  582. table = [
  583. 1 'バロールたわし',
  584. 'イグニスジッポ',
  585. 'ヤコ仮面or梟の文鎮(選択可)',
  586. 'ナレッジのハンモックorジンジャビースト',
  587. lambda { return normal3.to_s },
  588. lambda { return normal3.to_s },
  589. ]
  590. 1 result, = get_table_by_1d6(table)
  591. 1 return result
  592. end
  593. # ノーマルくじ表3
  594. 1 def normal3
  595. table = [
  596. 1 '特性HPポーション',
  597. '特性MPポーション',
  598. '黒い甲冑',
  599. '天体望遠鏡',
  600. '金獅子の剥製',
  601. 1 lambda { return normal4.to_s },
  602. ]
  603. 1 result, = get_table_by_1d6(table)
  604. 1 return result
  605. end
  606. # ノーマルくじ表4
  607. 1 def normal4
  608. table = [
  609. 1 '特性スタミナポーション',
  610. '戦乙女の兜',
  611. 'フェンリルの首輪',
  612. 'フェニックスカーペット',
  613. '動くアダマンゴーレム',
  614. 1 lambda { return normal5.to_s },
  615. ]
  616. 1 result, = get_table_by_1d6(table)
  617. 1 return result
  618. end
  619. # ノーマルくじ表5
  620. 1 def normal5
  621. table = [
  622. 1 'キャンディークッション',
  623. '屑鉄の金床',
  624. '薪割り王の斧',
  625. 'ロジエの水差し',
  626. '箱舟の模型',
  627. 1 lambda { return premium5.to_s },
  628. ]
  629. 1 result, = get_table_by_1d6(table)
  630. 1 return result
  631. end
  632. # プレミアムくじ表1
  633. 1 def premium1
  634. table = [
  635. 1 'プレミアムチキン',
  636. 'プレミアムチキン',
  637. 'プレミアムチキン',
  638. 1 lambda { return normal3.to_s },
  639. lambda { return premium2.to_s },
  640. lambda { return premium2.to_s },
  641. ]
  642. 1 result, = get_table_by_1d6(table)
  643. 1 return result
  644. end
  645. # プレミアムくじ表2
  646. 1 def premium2
  647. table = [
  648. '親衛隊バッジ',
  649. 'ハタモトチャブダイ',
  650. '星のコンパス',
  651. '白銀の甲冑',
  652. lambda { return normal4.to_s },
  653. lambda { return premium3.to_s },
  654. ]
  655. result, = get_table_by_1d6(table)
  656. return result
  657. end
  658. # プレミアムくじ表3
  659. 1 def premium3
  660. table = [
  661. '特性クイックHPポーション',
  662. '特性クイックMPポーション',
  663. '特製クイックスタミナポーション',
  664. '火龍のフィギュアor氷龍のフィギュア(選択可)',
  665. 'ヒメショーグンドレス',
  666. lambda { return premium4.to_s },
  667. ]
  668. result, = get_table_by_1d6(table)
  669. return result
  670. end
  671. # プレミアムくじ表4
  672. 1 def premium4
  673. table = [
  674. 'クイックユグドラポーション',
  675. '銀河龍のフィギュア/ドラゴン',
  676. '銀河龍のフィギュア/魔族',
  677. '魔族チェスセット',
  678. 'イグニスコンロ',
  679. lambda { return premium5.to_s },
  680. ]
  681. result, = get_table_by_1d6(table)
  682. return result
  683. end
  684. # プレミアムくじ表5
  685. 1 def premium5
  686. table = [
  687. 1 'グレヴディバリウス',
  688. '天使の望遠鏡orデスの目覚まし時計(選択可)',
  689. '世界樹の蔦',
  690. '死神の飾りドレス',
  691. 'ザバーニヤ等身大フィギュア',
  692. lambda { return premium6.to_s },
  693. ]
  694. 1 result, = get_table_by_1d6(table)
  695. 1 return result
  696. end
  697. # プレミアムくじ表6
  698. 1 def premium6
  699. table = [
  700. 'イレブンチキン',
  701. 'イレブンチキン(2ピース)',
  702. 'イレブンチキン(3ピース)',
  703. 'イレブンチキン(6ピース)',
  704. 'イレブンチキン(12ピース)',
  705. 'wish star',
  706. ]
  707. result, = get_table_by_1d6(table)
  708. return result
  709. end
  710. # GURPS-FW ナンバーワンくじ
  711. 1 def getLotResult(type)
  712. 2 then: 1 if type == "P"
  713. 1 premium1
  714. else: 1 else
  715. 1 normal1
  716. end
  717. end
  718. # GURPS-FW 夢幻の迷宮財宝テーブル(ver.2013/05/03)
  719. 1 def getTresureTable(num)
  720. 1 case num
  721. # 初級マイナス
  722. when: 0 when -1
  723. table = [
  724. 'HPポーション(消耗品)',
  725. 'MPポーション(消耗品)',
  726. 'スタミナポーション(消耗品)',
  727. '抵抗ポーション(消耗品)',
  728. 'マジックパウダー:無(消耗品)',
  729. '200GP',
  730. ]
  731. # 初級0-9
  732. when: 0 when 0
  733. table = [
  734. '高級HPポーション(消耗品)',
  735. '高級MPポーション(消耗品)',
  736. '高級スタミナポーション(消耗品)',
  737. '高級抵抗ポーション(消耗品)',
  738. 'マジックパウダー:銀(消耗品)',
  739. '600GP',
  740. ]
  741. # 初級10-19
  742. when: 0 when 1
  743. table = [
  744. '大地の守り(装飾品)',
  745. 'ファインウェポンケース(装飾品)',
  746. '狩人の羽帽子(装飾品)',
  747. '狙撃手の指貫(装飾品)',
  748. 'スタミナバンド・健康お守り・レザーマント3点セット(装飾品)',
  749. '1200GP',
  750. ]
  751. # 初級20-29
  752. when: 0 when 2
  753. table = [
  754. 'ミスリルダガーorミスリルシールドを選択(短剣or盾)',
  755. '高級クイック能力増加ポーション(消耗品)',
  756. '高級クイックHPポーション(消耗品)',
  757. '高級クイックMPポーション(消耗品)',
  758. '装飾品1つ(3000GPまでのもの)',
  759. '2000GP',
  760. ]
  761. # 初級30-39
  762. when: 1 when 3
  763. 1 table = [
  764. 'ミスリル武器(4000GPまでのもの)',
  765. '最高級能力増加ポーション(消耗品)',
  766. '高級クイック再生ポーション(消耗品)',
  767. '魔法1つ(5000GPまでのもの)',
  768. '防具1つ(5000GPまでのもの)',
  769. '3000GP',
  770. ]
  771. # 初級40-49
  772. when: 0 when 4
  773. table = [
  774. 'オサフネorサスケブレードを選択(刀)',
  775. 'アダマンダガー',
  776. '弓1つ(5000GPまでのもの)',
  777. 'ギロチンブレード(両手剣)',
  778. '装飾品1つ(5000GPまでのもの)',
  779. '4500GP',
  780. ]
  781. # 初級50-
  782. when: 0 when 5
  783. table = [
  784. 'アダマン武器(8000GPまでのもの)',
  785. 'アダマンシールド(盾)',
  786. 'ミスリルスケイル',
  787. '蘇生ポーション',
  788. '装飾品1つ(10000GPまでのもの)',
  789. '6000GP',
  790. ]
  791. # 初級最高
  792. when: 0 when 6
  793. table = [
  794. '武器1つ(612000GPまでのもの)',
  795. '盾1つ(12000GPまでのもの)',
  796. '鎧1つ(12000GPまでのもの)',
  797. '蘇生ポーション',
  798. '装飾品1つ(15000GPまでのもの)',
  799. '10000GP',
  800. ]
  801. # 中級最高
  802. when: 0 when 7
  803. table = [
  804. '武器1つ(30000GPまでのもの)',
  805. '盾1つ(30000GPまでのもの)',
  806. '鎧1つ(30000GPまでのもの)',
  807. '蘇生ポーション+特製クイックHPポーション(特製は人数分)',
  808. '装飾品1つ(40000GPまでのもの)',
  809. '25000GP',
  810. ]
  811. # 上級最高
  812. when: 0 when 8
  813. table = [
  814. '武器1つ(60000GPまでのもの)',
  815. '盾1つ(60000GPまでのもの)',
  816. '鎧1つ(60000GPまでのもの)',
  817. '蘇生ポーション+特製クイックポーション(特製は人数分、HP・MP・スタミナの3種)',
  818. '装飾品1つ(80000GPまでのもの)',
  819. '50000GP',
  820. ]
  821. # 悪夢最高
  822. when: 0 when 9
  823. table = [
  824. '武器1つ(150000GPまでのもの)',
  825. '盾1つ(150000GPまでのもの)',
  826. '鎧1つ(150000GPまでのもの)',
  827. 'クイック蘇生ポーション+特製クイックポーション(特製は人数分、HP・MP・スタミナの3種)',
  828. '装飾品1つ(200000GPまでのもの)',
  829. '黄金の守護者の証(装飾品)+黄金の電子暗号キー(装飾品)',
  830. ]
  831. else: 0 else
  832. table = nil
  833. end
  834. 1 return table
  835. end
  836. # トラップリスト(ver.2013/11/07)
  837. 1 def getTrapTable(diff)
  838. 1 case diff
  839. when: 1 when "E" # 初級
  840. 1 dif = "初級"
  841. 1 d = 0
  842. when: 0 when "N" # 中級
  843. dif = "中級"
  844. d = 1
  845. when: 0 when "H" # 上級
  846. dif = "上級"
  847. d = 2
  848. when: 0 when "L" # 悪夢
  849. dif = "悪夢"
  850. d = 3
  851. else: 0 else
  852. dif = nil
  853. d = nil
  854. end
  855. table = [
  856. 1 "トライディザスター:宝箱から広範囲に火炎・冷気・電撃が放たれる。PC全員に火炎により#{['3D', '4D', '5D', '7D'][d]}の「叩き」ダメージ、冷気により#{['3D', '4D', '5D', '7D'][d]}の「叩き」ダメージ、電撃により['2D', '3D', '4D', '6D']の「叩き」ダメージを与える(電撃は金属鎧の防護点無視)",
  857. "ペトロブラスター:宝箱を開けたキャラクターに《肉を石》をかける。技能レベルは#{['20', '22', '24', '30'][d]}。",
  858. "クロスボウストーム:宝箱から矢の嵐が放たれる罠。PC全員に#{['2D', '3D', '5D', '8D'][d]}の「刺し」ダメージを与える。盾の受動防御を無視した「よけ#{['', '-2', '-4', '-8'][d]}」で回避が可能。",
  859. "フォーチュンイーター:PC全員の幸運を食らい、フォーチュンを#{['1', '2', '3', '5'][d]}減少させる。フォーチュンが0の場合#{['3D', '6D', '9D', '15D'][d]}の防護点無視ダメージを受ける。",
  860. "スロット:スロットが揃うまで開かない宝箱。スロットを1回まわすには#{['100', '300', '500', '1000'][d]}GPが必要。行動を消費して「視覚#{['-5', '-7', '-9', '-13'][d]}」判定に成功すればスロットはそろう。「反射神経」があれば「視覚」そのままで判定可能。",
  861. "テレポーター:宝箱の周囲に存在するPC全員(とエンカウントしているモンスター)をダンジョン入口方面に転送する。深度が#{['3D減少する', '4D減少する', '5D減少する', '0になる'][d]}。",
  862. "アイスコフィン:宝箱を開けようとしたキャラクターに冷気で#{['3D', '5D', '7D', '12D'][d]}の「叩き」ダメージを与え更に最終的なダメージの半分のFPダメージを与える。",
  863. "クロスボウ:宝箱を開けようとしたキャラクターに#{['2D', '3D', '5D', '8D'][d]}の「刺し」ダメージを与える。盾の受動防御を無視した「よけ#{['', '-2', '-4', '-8'][d]}」で回避が可能。",
  864. "毒針:宝箱を開けようとしたキャラクターに#{['1D', '2D', '3D', '6D'][d]}の「刺し」ダメージを与える。1点でもダメージを受けると「生命力#{['-4', '-5', '-6', '-8'][d]}」で判定を行い、失敗すると1日間すべての判定に-2のペナルティを受ける。盾の受動防御を無視した「よけ#{['', '-2', '-4', '-8'][d]}」で回避が可能。",
  865. "アラーム:即座にその地形のエンカウント表(イベント表4-1~4-6)を振る。",
  866. "殺人鬼の斧:宝箱を開けようとしたキャラクターに#{['3D', '4D', '6D', '10D'][d]}の「切り」ダメージを与える。命中部位は「ランダム部位命中表」を用いて決定すること。盾の受動防御を無視した「よけ#{['', '-2', '-4', '-8'][d]}」で回避が可能。",
  867. "死神:宝箱を開けようとしたキャラクターにネクロマンサーの呪術【憑物】+【死神】の効果を与える。3ラウンドすべての判定に#{['-1', '-2', '-3', '-4'][d]}のペナルティを受け、効果が切れると同時に#{['3D+3', '3D+6', '3D+9', '3D+15'][d]}の防護点無視ダメージを受ける。",
  868. "幻の宝:宝箱は二重底になっている。「知力#{['-5', '-7', '-9', '-13'][d]}」か<商人#{['', '-2', '-4', '-8'][d]}>の判定に失敗すると、重さ10kgの価値のない偽の宝物を入手してしまう。偽の宝物はシナリオ終了まで捨てることはできないが「トレジャーイーター」の罠にかかると消滅する。",
  869. "エクスプロージョン:宝箱が爆発し、PC全員に#{['4D', '6D', '9D', '15D'][d]}の「叩き」ダメージを与える。宝箱の中身は粉々になる。",
  870. "レインボーポイズン:宝箱から七色の毒ガスが放たれる。PC全員が「生命力#{['-4', '-5', '-6', '-8'][d]}」で判定を行い、失敗するとHP、MP、FPに#{['2D', '3D', '4D', '6D'][d]}の防護点無視ダメージを受ける。",
  871. "デスクラウド:宝箱から致死性の毒ガスが放たれる。PC全員が「生命力#{['-4', '-5', '-6', '-8'][d]}」で判定を行い、失敗したPCは即座に死亡する。",
  872. ]
  873. 1 return dif, table
  874. end
  875. # ランダムイベント表(ver.2013/11/07)
  876. 1 def getRandomEvent(dice1, dice2, diff)
  877. 2 case diff
  878. when: 1 when "E"
  879. 1 dif = "初級"
  880. 1 d = 0
  881. when: 0 when "N"
  882. dif = "中級"
  883. d = 1
  884. when: 1 when "H"
  885. 1 dif = "上級"
  886. 1 d = 2
  887. when: 0 when "L"
  888. dif = "悪夢"
  889. d = 3
  890. else: 0 else
  891. dif = ""
  892. d = nil
  893. end
  894. 2 case dice1
  895. when: 1 when 1
  896. 1 area = "洞窟"
  897. 1 case dice2
  898. when: 0 when 1
  899. table = [
  900. "回復の泉。PC全員のHP・MP・FPが完全に回復する。気絶・朦朧状態も回復。",
  901. "淡い光を放つ鉱石に包まれた部屋に出る。フォーチュンが#{getRandomDiff(dice1, 12, d, 0)}点回復する。",
  902. "天井が開いていて植物の育っている洞窟内庭園。#{getRandomDiff(dice1, 13, d, 0)}に成功すると力の沸く木の実を見つけHP・FP・MPを#{getRandomDiff(dice1, 13, d, 1)}点回復できる。",
  903. "洞窟内で栽培できる特殊なキノコを栽培するフラウに出会う。100GP支払うことでキノコを1つ譲ってもらうことができ、シナリオ終了まで《怪力2》《すばやさ2》《知恵2》《活力2》のいずれかの効果を得る(ランダム)このキノコは持ち帰ることはできず、2つめを食べても効果はない。",
  904. "ギア技術を用いた強力な懐中電灯のおいてある休憩室。迷宮を出るまで洞窟の深度判定で「暗視」があるものとして扱う。迷宮を出ると懐中電灯は寿命が来たのか壊れてしまう。",
  905. "不思議な光を放つ水が沸いている。パーティーメンバーのHP・MP・FPのいずれかが減少している場合このイベントは拒否できない。また、全快でも「好奇心」を持つキャラクターは知力判定に失敗すると飲みにいこうとする。飲んだキャラクターは1Dを振り、以下のような効果が発生する。ロールプレイが面白かった場合シナリオ終了時に1CPのボーナスを与えてもよい。
  906. ----------
  907. 1:HP・MP・FP全回復
  908. 2:シナリオ終了まで肉体的に不利な特徴が1つ消滅する
  909. 3:シナリオ終了まで精神的に不利な特徴が1つ消滅する
  910. 4:HP・MP・FPが現在地の半分になる HPがマイナスの場合はHP・MP・FP全回復
  911. 5:シナリオ終了まで余分な獣っぽい耳や尻尾が生える 聴覚判定+4
  912. 6:シナリオ終了まで性別が男女入れ替わる。
  913. ----------",
  914. ]
  915. when: 0 when 2
  916. table = [
  917. "財宝(カギ・トラップなし)。財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  918. "財宝(カギつき。行動を消費して#{getRandomDiff(dice1, 22, d, 0)}に成功すれば開く)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  919. "財宝(カギなし、トラップつき。行動を消費して#{getRandomDiff(dice1, 23, d, 0)}に成功すれば解除可能)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  920. "財宝(カギ、トラップつき。行動を消費して#{getRandomDiff(dice1, 24, d, 0)}に成功すれば解除可能)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  921. "ミミックの罠。ランダムなキャラクターに3Dの「切り」ダメージを与える。#{getRandomDiff(dice1, 25, d, 0)}に成功すればこの罠を見抜いて無効化することができ、なおかつ「深度×#{getRandomDiff(dice1, 25, d, 1)}」GPを入手可能。",
  922. "トレジャーイーターの罠。冒険中に入手したアイテム(消耗品・GP以外)を全て失う。#{getRandomDiff(dice1, 26, d, 0)}に成功すればこの罠を見抜いて無効化することができる。",
  923. ]
  924. when: 0 when 3
  925. table = [
  926. "洞窟内で近道を発見。深度が1D+1増加する。",
  927. "洞窟内で近道を発見。深度が1D増加する。細い道のため、体の大きなキャラクター(STが13以上)は、通るのに苦労してFPを1点消耗する",
  928. "分かれ道。2分の1の確率で深度が1D増加する。「方向感覚」があれば必ず増加。",
  929. "足場の悪い近道。PTの誰かが#{getRandomDiff(dice1, 34, d, 0)}に成功すれば深度が1D増加する。失敗した場合は#{getRandomDiff(dice1, 34, d, 1)}の「叩き」ダメージを受ける",
  930. "大きな岩でふさがれた近道。1ラウンドで破壊することができれば深度が1D増加する。岩はどのヘクスからでも攻撃可能。分類:岩石、防護点8、#{getRandomDiff(dice1, 35, d, 0)}、切り刺しダメージボーナス無効。",
  931. "道が3つに分かれている。1Dで1、2が出るとペナルティなし、1Dで3、4が出ると深度-2、1Dで5、6が出ると深度-4。「直感」があれば、#{getRandomDiff(dice1, 36, d, 0)}の判定に成功すれば正しい道を選択可能。",
  932. ]
  933. when: 1 when 4
  934. table = [
  935. 1 "#{getRandomDiff(dice1, 41, d, 0)}とエンカウント。2ラウンド経過するとキャンディークラウンは戦場全域に《べたべた》をかけて逃亡する。",
  936. "#{getRandomDiff(dice1, 42, d, 0)}彼らはお互いに争っているがPCたちを見つけると向きを変えて襲い掛かってくる。#{getRandomDiff(dice1, 42, d, 1)}",
  937. "#{getRandomDiff(dice1, 43, d, 0)}相手は洞窟では巧妙に擬態しており、【ハイドインシャドウ】状態とみなす。#{getRandomDiff(dice1, 43, d, 1)}",
  938. "#{getRandomDiff(dice1, 44, d, 0)}トロッコに乗って逃げつつの戦闘になり、2ラウンド以内に倒せなければ轢かれてPC全員が#{getRandomDiff(dice1, 44, d, 1)}の防護点無視ダメージを受ける。また、1ラウンドに1人誰かが体力判定を行ってトロッコを運転する必要があり、これに失敗すると即座に轢かれてしまう。轢かれると戦闘は終了する。パーテイー内にケイヴウォーカーがいればこの判定は不要。",
  939. "炎の燃え盛る洞窟。深度判定直前に炎で#{getRandomDiff(dice1, 45, d, 0)}の「叩き」ダメージを受ける。さらに#{getRandomDiff(dice1, 45, d, 1)}とエンカウント。火炎弱点のモンスターがいれば即座に逃亡する。",
  940. "冷気に包まれた洞窟。深度判定直前に冷気で#{getRandomDiff(dice1, 46, d, 0)}のFPダメージを受ける(防護点無視)さらに#{getRandomDiff(dice1, 46, d, 1)}とエンカウント。冷気弱点のモンスターがいれば即座に逃亡する。",
  941. ]
  942. when: 0 when 5
  943. table = [
  944. "落盤がモンスターを押しつぶす。戦闘中の場合ランダムなモンスター1人を即死させる。APやドロップ品も入手可能。それ以外の場合は特に何も起きない。",
  945. "採掘用のダイナマイトが打ち捨てられている。行動ターンを消費して使用することで任意の半径#{getRandomDiff(dice1, 52, d, 0)}の敵味方全員に#{getRandomDiff(dice1, 52, d, 1)}の「叩き」ダメージを与える。命中判定は自動的に0成功とし、《爆裂火球》と同様にダメージの軽減が可能。",
  946. "有毒ガスが発生している。分類「ギア」「アンデッド」以外のキャラクターは敵味方全員#{getRandomDiff(dice1, 53, d, 0)}で判定を行い、失敗度分のダメージを受ける。《空気浄化》などがあれば使用することで無効化できる。",
  947. "溶岩の流れる部屋。深度判定直前に炎で#{getRandomDiff(dice1, 54, d, 0)}の「叩き」ダメージを受ける。深度判定を行い、失敗したキャラクターはさらに追加で#{getRandomDiff(dice1, 54, d, 0)}の「叩き」ダメージを受ける。",
  948. "落盤がPCのうちランダムに1人を押しつぶす。受動防御無視の#{getRandomDiff(dice1, 55, d, 0)}に失敗すると#{getRandomDiff(dice1, 55, d, 1)}の「叩き」ダメージを受ける。パーティーの誰かが「第六感」か「視覚-5」の判定に成功すれば事前に回避可能。(「暗視」があれば「視覚-2」でも判定可能)",
  949. "進んできた道の後方が急に崩落する。ダンジョン攻略が完了するまで「撤退」ができなくなるが、「深度」が現時点より下がることがなくなる。",
  950. ]
  951. when: 0 when 6
  952. table = [
  953. "プラネタリウムのように鉱石が輝く部屋。星の配置に関する謎かけになっている。行動を消費して#{getRandomDiff(dice1, 61, d, 0)}に成功すればこの謎を解くことができる。謎が解けると#{getRandomDiff(dice1, 61, d, 1)}が入手できる。",
  954. "地熱で温泉が湧いている。このイベントが発生するとモンスターは消滅する。みんなで温泉に浸かることでFPが全回復する。また、温泉の薬効により受けていた毒は無効化され、ラウンドの最初にHPが#{getRandomDiff(dice1, 62, d, 0)}点ずつ回復するようになる。",
  955. "地下渓流を発見する。深度判定が体力判定ではなく<水泳>判定になる。深度判定に#{getRandomDiff(dice1, 63, d, 0)}成功以上した場合は地底湖に沈む財宝を発見可能。財宝にカギやトラップはなく、中身は深度そのままの財宝テーブルを使用する。",
  956. "アダマン鉱脈を発見する。「<採掘>の成功度×深度×#{getRandomDiff(dice1, 64, d, 0)}」GP分のアダマン鉱石を入手可能。複数人数で判定を行えばその回数分入手可能。ただし50GP分ごとに重量が1kg。撤退・全滅した場合アダマン鉱石は消滅する。",
  957. "強烈な磁力を放つ鉱石のある部屋。金属製の防具は重量を2倍に計算する。続いてエンカウント表(4-1~4-6)を振ること。なお、4-5の部屋の炎と4-6の部屋の冷気による効果は適用しない。",
  958. "怪しい光を放つ鉱石の部屋。鉱石は無生物を破壊する振動を放っており、武器に#{getRandomDiff(dice1, 66, d, 0)}の効果を与える。また、種族「ギア」のキャラクターも同様の効果を受ける。ラウンド終了前に鉱石を破壊すればこの効果は受けない。鉱石はどのヘクスからでも攻撃可能。分類:岩石、防護点8、HP#{getRandomDiff(dice1, 66, d, 1)}、切り刺しダメージボーナス無効。",
  959. ]
  960. else: 0 else
  961. table = nil
  962. end
  963. when: 0 when 2
  964. area = "遺跡"
  965. case dice2
  966. when: 0 when 1
  967. table = [
  968. "回復の泉。PC全員のHP・MP・FPが完全に回復する。気絶・朦朧状態も回復。",
  969. "随分進んだし一休みしよう。深度が奇数の場合はFPが#{getRandomDiff(dice1, 12, d, 0)}回復。深度が偶数の場合は進んだように見せかけて迷っているだけだった。深度が1D減少する。",
  970. "どうやらここは古代の医務室らしい。#{getRandomDiff(dice1, 13, d, 0)}に成功すればPC全員のHP・MP・FPが完全に回復する。気絶・朦朧状態も回復。",
  971. "「道標のヒカリゴケ」を栽培しているフラウに出会う。300GPを払うと、以後の深度増加判定に+1のボーナスを得る。",
  972. "ダンジョンの見取り図を書いた部屋に出る。次のランダムイベントでは、好きな地形を選択してからイベント表を振ることができる。次が最終イベントだった場合、ラウンド終了時の深度判定に+2のボーナスを得る。",
  973. "「パワーアップ装置!」と書かれた怪しげな機械が置いてある。#{getRandomDiff(dice1, 16, d, 0)}を支払って使用するとキャラクターを強化(?)可能。使用するかは自由だが、「好奇心」を持つキャラクターは知力判定に失敗すると使用する。使用したキャラクターは1Dを振り、以下のような効果が発生する。
  974. ----------
  975. 1:能力値が1点上昇する。上がる能力値はランダムで1つ。CP総計はそれに応じて増加する
  976. 2:お肌がピチピチになり、容貌が1段階上昇する。「超美形」の場合さらに反応が男女とも+1(+5CP)
  977. 3:習得している技1つを選択して強化する。ソーサルギアは#{getRandomDiff(dice1, 16, d, 1)}までの魔法を1つ習得する
  978. 4:装置は突然大爆発を起こす!#{getRandomDiff(dice1, 16, d, 2)}の「叩き」ダメージを受ける
  979. 5:「鋭敏感覚1」が身につく。すでに「鋭敏感覚」がある場合そのレベルが上昇する
  980. 6:能力値が1点下降する。下がる能力値はランダムで1つ。CP総計はそれに応じて減少する
  981. ----------",
  982. ]
  983. when: 0 when 2
  984. table = [
  985. "財宝(カギ・トラップなし)。財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  986. "財宝(カギつき。行動を消費して#{getRandomDiff(dice1, 22, d, 0)}に成功すれば開く)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  987. "財宝(カギなし、トラップつき。行動を消費して#{getRandomDiff(dice1, 23, d, 0)}に成功すれば解除可能)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  988. "財宝(カギ、トラップつき。行動を消費して#{getRandomDiff(dice1, 24, d, 0)}に成功すれば解除可能)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  989. "ミミックの罠。ランダムなキャラクターに3Dの「切り」ダメージを与える。#{getRandomDiff(dice1, 25, d, 0)}に成功すればこの罠を見抜いて無効化することができ、なおかつ「深度×#{getRandomDiff(dice1, 25, d, 1)}」GPを入手可能。",
  990. "トレジャーイーターの罠。冒険中に入手したアイテム(消耗品・GP以外)を全て失う。#{getRandomDiff(dice1, 26, d, 0)}に成功すればこの罠を見抜いて無効化することができる。",
  991. ]
  992. when: 0 when 3
  993. table = [
  994. "鏡に映る怪人が自分の真似をしろとジェスチャーしている#{getRandomDiff(dice1, 31, d, 0)}のいずれかに成功すると鏡が消滅して隠し通路が開かれ、深度が2D増加する。",
  995. "小さな魔将の像がフィルトウィズの地図の上で乱雑に置かれている。#{getRandomDiff(dice1, 32, d, 0)}で判定を行い、魔将の所在地を正しく配置すると隠し通路が開かれ、深度が2D増加する。",
  996. "シュートの罠に引っかかるが、結果的に新たな道を発見する。深度が2D増加するが、PC全員が増加した深度#{getRandomDiff(dice1, 33, d, 0)}「叩き」ダメージを受ける。<軽業>で判定を行い、その成功度分ダメージを軽減可能。",
  997. "ラダマンティス崇拝者が作り出した、巨大な甲羅のようなものが置かれた部屋。登っていけば近道することができそうだ。#{getRandomDiff(dice1, 34, d, 0)}に成功すれば深度が1D増加する。",
  998. "後ろから重い物が転がってくる音がする。ローリングストーンだ!#{getRandomDiff(dice1, 35, d, 0)}で判定を行い、失敗したPCは#{getRandomDiff(dice1, 35, d, 1)}の「叩き」ダメージを受ける。全員成功だった場合のみ深度が2D増加する。",
  999. "通路が入り組んでおり道に迷いそうだ。#{getRandomDiff(dice1, 36, d, 0)}の判定に失敗すると深度が2D減少する。「方向感覚」があればこの影響は受けない。",
  1000. ]
  1001. when: 0 when 4
  1002. table = [
  1003. "#{getRandomDiff(dice1, 41, d, 0)}とエンカウント。2ラウンド経過するとキャンディークラウンは戦場全域に《べたべた》をかけて逃亡する。",
  1004. "石像が並ぶ通路がある。1Dを振って1・2・3なら#{getRandomDiff(dice1, 42, d, 0)}。1Dを振って4・5・6・の場合ガーゴイルに似ている、ただの石像。<モンスター知識-5>か「第六感」の判定に成功していなければ必ず相手の先制攻撃になり、その際PC先手で進行中の場合もモンスター先手に変更される。#{getRandomDiff(dice1, 42, d, 1)}",
  1005. "障害物に隠れて#{getRandomDiff(dice1, 43, d, 0)}が狙撃してくる。モンスターのすぐ傍には合計5ヘクスの障害物(防護点5、HP35。形はGMが任意に決定する)がある。障害物ごしに攻撃するには射撃武器でなくてはならず、射撃武器も命中に-2のペナルティを受ける。",
  1006. "ブツゼンにモンスターが仁王立ちをしており、問答を行ってくる。#{getRandomDiff(dice1, 44, d, 0)}に成功すると戦闘を回避することができ、APとドロップ品も入手可能。失敗するか戦闘を望んだ場合#{getRandomDiff(dice1, 44, d, 1)}とエンカウントする。",
  1007. "進路上に鎖に繋がれたモンスターを発見する。迂回して戦闘を避けるなら深度1D減少し、戦闘して倒すと深度が1D増加する。戦闘を行う場合#{getRandomDiff(dice1, 45, d, 0)}とエンカウントする。",
  1008. "暴れゴーレムが襲いかかってくる!《倍速》の魔法がかかった#{getRandomDiff(dice1, 46, d, 0)}とエンカウントする。このゴーレムは暴走の負荷によりターンの最初にHPが#{getRandomDiff(dice1, 46, d, 1)}減少する。",
  1009. ]
  1010. when: 0 when 5
  1011. table = [
  1012. "毒矢が飛んでくる。#{getRandomDiff(dice1, 51, d, 0)}に失敗すると#{getRandomDiff(dice1, 51, d, 1)}の「刺し」ダメージを受け、1点でもダメージを受けた場合#{getRandomDiff(dice1, 51, d, 2)}判定を行い失敗すると以後ターンの最初に#{getRandomDiff(dice1, 51, d, 3)}の防護点無視ダメージを受ける。",
  1013. "毒霧が部屋に散布される。#{getRandomDiff(dice1, 52, d, 0)}で判定を行い、失敗すると《解毒》などを使用しない限り以後の判定全てに-2のペナルティを受ける。《空気浄化》があれば防御タイミングで使用して打ち消すことができる。",
  1014. "フロアイミテーターだ!この部屋自体が魔物である。ロックバトラー(#{getRandomDiff(dice1, 53, d, 0)})とエンカウントする。このモンスターがいる限り移動はできず、ラウンドごとの地形変化や深度増加も行わない。PCとフロアイミテーターは常に隣接しているものとして扱う。",
  1015. "どうやら休憩室のようだ、ふわふわのベッドもある。#{getRandomDiff(dice1, 54, d, 0)}判定に失敗すると転倒状態になり、ダメージを受けるか行動を消費して起こしてもらうまで行動不能。全員失敗した場合、君たちの冒険はここまでだ。せめていい夢を見れるといいだろう(保険は適用可能)",
  1016. "ラダマンティスの蛇の像と目が合う。どうやらダンジョンの監視者に見つかってしまったらしい!以後モンスターとエンカウントする場合、その数が2倍となる(この効果は累積する)なお、ネームドもしくは魔将の数は変化しない。",
  1017. "怪しげな卵が1つ置かれている。GMは#{getRandomDiff(dice1, 56, d, 0)}の中から好きなものを1体選びエンカウントさせることができる。深度が0の場合、卵の中から1段階高い財宝テーブルのアイテムが手に入る。",
  1018. ]
  1019. when: 0 when 6
  1020. table = [
  1021. "突如持っていた灯が消えて真っ暗になってしまう。暗闇を見通せる手段(特徴「暗視」、魔法《持続光》、遺跡1-4のヒカリゴケなど)がない限り、PCはこのラウンド中の敏捷力に-4のペナルティを受ける。(ストームコーザーは-8)",
  1022. "どうやら過去の訓練施設のようだ。「パンチングマシーン」と書かれたものがあり、100GP払って挑戦可能。武器を外した状態での「叩き」ダメージを求め、値が大きいと景品が入手可能。1回挑戦すると、ガタがきていたのか壊れてしまう。<格闘><猫格闘><空手>の技を使用しても構わない。
  1023. ---------
  1024. ダメージが#{getRandomDiff(dice1, 62, d, 0)}以上:2D×50GP
  1025. ダメージが#{getRandomDiff(dice1, 62, d, 1)}以上:深度が1段階低い財宝テーブル
  1026. ダメージが#{getRandomDiff(dice1, 62, d, 2)}以上:深度が1段階高い財宝テーブル
  1027. ---------",
  1028. "謎の装置のせいで気になるあの子と体が入れ替わってしまった!?シナリオ終了までPCのうち2人の体が入れ替わってしまい、精神的な特徴と癖が入れ替わってしまう。なぜか知力や技能はそのまま。プレイヤーは入れ替わった相手の性格を演じること。入れ替わる2人はランダムに決定するか面白くなるようにGMが選ぶ。展開が面白かった場合、GMはシナリオクリア時のCPを1点追加しても良い。",
  1029. "古代のテクノロジーを使用した医療施設だ。このイベントが発生するとモンスターは消滅する。#{getRandomDiff(dice1, 64, d, 0)}に成功すると全員のHP・FP・MPと転倒以外の状態異常を全回復できる。また、シナリオ終了まで不利な肉体的・精神的な特徴を無効化できる。",
  1030. "キャンディークラウンハウスだ!キャンディークラウン(CL40)×1D#{getRandomDiff(dice1, 65, d, 0)}とエンカウントする。もし1体も倒せなかった場合、1体も倒せずチャンスをものにできなかった悔しさからFPに出てきたキャンディークラウンの数Dのダメージを受ける(軽減不可)",
  1031. "なぜここに呼ばれたかおわかりになりますでしょうか?ラダマンティス崇拝者の作り出した審判の部屋。<地域知識/フィルトウィズ全域-3>に成功すると罰を与える部屋だとわかり、部屋の中央のラダマンティス像を攻撃できるようになる。像はどのヘクスからでも攻撃可能。分類:岩石、防護点8、HP#{getRandomDiff(dice1, 66, d, 0)}、切り刺しダメージボーナスなし。2ラウンド以内に破壊すれば現在の深度に等しいAPを入手可能。破壊できなかった場合像から裁きの光が放たれ、PC全員が「#{getRandomDiff(dice1, 66, d, 1)}」点の防護点無視ダメージを受ける。",
  1032. ]
  1033. else: 0 else
  1034. table = nil
  1035. end
  1036. when: 1 when 3
  1037. 1 area = "断崖"
  1038. 1 case dice2
  1039. when: 1 when 1
  1040. table = [
  1041. 1 "回復の泉。PC全員のHP・MP・FPが完全に回復する。気絶・朦朧状態も回復。",
  1042. "休憩に丁度いい広場を見つけた。FPが2D回復するが、#{getRandomDiff(dice1, 12, d, 0)}判定を行うこと。PCの半数以上が失敗すると居心地が良すぎて離れづらくなり次の深度判定と地形変化が起きなくなる。その場合次もこのイベントを行うこと。",
  1043. "山小屋を発見し一休み。HPとFPが#{getRandomDiff(dice1, 13, d, 0)}回復する。4人で休んでいる場合暇つぶしに山小屋の四隅をぐるぐるまわって運動し始めるが、後から妙なことに気が付きMPが1D減少する。",
  1044. "キイチゴを栽培しているフラウに出会う。栄養満点。50GP払うことでFPとMPを#{getRandomDiff(dice1, 14, d, 0)}回復することができる(1人1回)",
  1045. "少し休憩できそうな洞窟を発見する。中には他のエクスプローラーが残していったと思われる道具もあった。#{getRandomDiff(dice1, 15, d, 0)}GPまでの好きな消耗品1つを入手して、大雨が降っていればそれも止む。",
  1046. "回復の泉。しかし山間の貴重な水源のため、亜人によって管理されており使用させてもらうには#{getRandomDiff(dice1, 16, d, 0)}GPが必要。パーティーに管理している亜人と同じ種族がいれば無料で使用可能。使用するとPC全員のHP・MP・FPが完全に回復する。気絶・朦朧状態も回復。どの種族が管理しているかは1Dを振って決定する。
  1047. ----------
  1048. 1:ドラコニアン
  1049. 2:リザードとワイズマン
  1050. 3:フラウ
  1051. 4:シルヴァテイル
  1052. 5:ストームコーザー
  1053. 6:グラント
  1054. ----------",
  1055. ]
  1056. when: 0 when 2
  1057. table = [
  1058. "財宝(カギ・トラップなし)。財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1059. "財宝(カギつき。行動を消費して#{getRandomDiff(dice1, 22, d, 0)}に成功すれば開く)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1060. "財宝(カギなし、トラップつき。行動を消費して#{getRandomDiff(dice1, 23, d, 0)}に成功すれば解除可能)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1061. "財宝(カギ、トラップつき。行動を消費して#{getRandomDiff(dice1, 24, d, 0)}に成功すれば解除可能)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1062. "ミミックの罠。ランダムなキャラクターに3Dの「切り」ダメージを与える。#{getRandomDiff(dice1, 25, d, 0)}に成功すればこの罠を見抜いて無効化することができ、なおかつ「深度×#{getRandomDiff(dice1, 25, d, 1)}」GPを入手可能。",
  1063. "トレジャーイーターの罠。冒険中に入手したアイテム(消耗品・GP以外)を全て失う。#{getRandomDiff(dice1, 26, d, 0)}に成功すればこの罠を見抜いて無効化することができる。",
  1064. ]
  1065. when: 0 when 3
  1066. table = [
  1067. "ショートカットコースを発見。#{getRandomDiff(dice1, 31, d, 0)}に成功すると深度が2D増加する。",
  1068. "鉱物を運んでいたのであろう、運搬用トロッコのレールを発見する。深度が1D増加する。ケイブウォーカーがいる場合#{getRandomDiff(dice1, 32, d, 0)}で判定を行い、更にその成功度分深度が増加する。",
  1069. "険しい斜面が続く。#{getRandomDiff(dice1, 33, d, 0)}に失敗すると道の選択を誤り深度が1D、FPが1点減少する。",
  1070. "空を飛べればショートカットできそうな崖を発見する。なんらかの飛行手段のあるPCがいる場合深度が2D増加する。(魔法などの場合その分のMPを消費すること。1人分でよい)飛行手段がなければ遠回りになり、深度が1D減少する。",
  1071. "遠くから山彦のような不思議な声が聞こえる。#{getRandomDiff(dice1, 35, d, 0)}に成功すると何者かが迷いやすい道を注意してくれているのがわかる。判定に失敗した場合、深度が1D減少する。",
  1072. "急に突風が吹いてきた!全員で#{getRandomDiff(dice1, 36, d, 0)}判定を行うこと。失敗したキャラクターは急斜面を落下して3Dの「叩き」ダメージを受ける。また、「失敗したPCの人数×1D」の深度が減少する。",
  1073. ]
  1074. when: 0 when 4
  1075. table = [
  1076. "#{getRandomDiff(dice1, 41, d, 0)}とエンカウント。2ラウンド経過するとキャンディークラウンは戦場全域に《べたべた》をかけて逃亡する。",
  1077. "あれはストームコーザー?・・・いや、魔物だ!#{getRandomDiff(dice1, 42, d, 0)}。うまく地形を利用して幻惑してくるため、この敵からの回避には-2のペナルティを受ける。",
  1078. "登山訓練中の魔族の小隊と出くわす。相手は疲れているようだ?#{getRandomDiff(dice1, 43, d, 0)}とエンカウント。FPは最大値の半分まで減少している。",
  1079. "突然魔族が飛びかかってきた!#{getRandomDiff(dice1, 44, d, 0)}。体の一部が宝石でできており、普通の#{getRandomDiff(dice1, 44, d, 1)}とは異なるようだ。撃破時に入手できるAPが2倍で、ドロップ判定のダイスが良い方に1点修正される。#{getRandomDiff(dice1, 44, d, 2)}",
  1080. "ケタケタ笑いながら空から襲撃をされる。#{getRandomDiff(dice1, 45, d, 0)}。彼女達はとても飽きっぽいので2ラウンド行動したあと深度判定の際に立ち去ってしまう(APとドロップは入手できない)#{getRandomDiff(dice1, 45, d, 1)}",
  1081. "#{getRandomDiff(dice1, 46, d, 0)}の縄張りに足を踏み入れる#{getRandomDiff(dice1, 46, d, 1)}。引き返して一度縄張りを離れるなら深度が2D減少する。そのまま進むのであればPC全員で反応判定を行うこと。(反応修正は容貌も含め全て適用。同性とみなす)1人でも「良い」以上の反応であれば見逃してもらえる。全員が「普通」以下の場合は戦闘になる。",
  1082. ]
  1083. when: 0 when 5
  1084. table = [
  1085. "ジャーンジャーン!げぇ、落石だ!!魔族がここぞとばかりに岩を落とし始める。#{getRandomDiff(dice1, 51, d, 0)}の判定に失敗したPCは#{getRandomDiff(dice1, 51, d, 1)}の「叩き」ダメージを受ける。「第六感」に事前に成功していれば全員が回避可能。",
  1086. "ファイトー!いっぱーつ!!足場が崩れ出す。#{getRandomDiff(dice1, 52, d, 0)}に失敗したPCは落下して#{getRandomDiff(dice1, 52, d, 1)}の「叩き」ダメージを受ける。成功したPCは体力判定を行い、落下するキャラを支えることができる。この判定に失敗した場合支えようとしたキャラクターも一緒にダメージを受ける。",
  1087. "滑りやすい岩を飛び移っていく道が続いている。敵味方全員が#{getRandomDiff(dice1, 53, d, 0)}判定を行い、失敗したキャラクターは転倒してFPに1点のダメージを受ける。浮遊・飛行して移動しているキャラクターはこの影響を受けない。#{getRandomDiff(dice1, 53, d, 1)}",
  1088. "『銀糸の甲殻』アルゲントゥムの巣が張られている。幸い主はいないようだ・・・?1Dを振って3以下だった敵味方全員はソーサルギアの《べたべた》の効果を受ける。#{getRandomDiff(dice1, 54, d, 0)}",
  1089. "美しい万年雪の中を進んでいたと思ったのも束の間、雪崩に遭遇してしまう!#{getRandomDiff(dice1, 55, d, 0)}か「第六感」に誰かが成功すれば回避可能。失敗すると敵味方全員が#{getRandomDiff(dice1, 55, d, 1)}の防護点無視ダメージ、その半分のFPダメージを受ける。",
  1090. "下から魔族が大量に登ってくる、今のうちに撃退しなくては。魔族の群れは「分類:魔族、#{getRandomDiff(dice1, 56, d, 0)}、ダメージボーナス有効」とみなし、どのヘクスからも攻撃可能。ラウンド終了後の深度判定時に、PC全員が「残りHP÷2」の防護点無視ダメージを受ける。シナリオ終了時に「与えたダメージ合計÷2」に等しいAPを得ることができる。",
  1091. ]
  1092. when: 0 when 6
  1093. table = [
  1094. "急に大雨が降り出した、屋外に避難したいところだが・・・地形が「洞窟」か「遺跡」に変更されるまで深度判定の成功度に#{getRandomDiff(dice1, 61, d, 0)}のペナルティを受ける。",
  1095. "カラーストーンの原石を見つける。行動ターンを消費して<採掘>か<技師/魔道具ー5>の判定を行い、「成功度×#{getRandomDiff(dice1, 62, d, 0)}GP」を入手することができる。クリティカル時は成功度を3倍に計算する。",
  1096. "不思議な岩がある。1Dを振って1・2であれば火炎、3・4であれば冷気、5・6であれば電撃特性の攻撃で破壊可能。#{getRandomDiff(dice1, 63, d, 0)}行動ターンを消費して岩を狙うと宣言すればよい。岩は全てのヘクスから攻撃可能で、破壊したあとには財宝が発見できる。財宝の中身は現在の深度に応じた財宝テーブルを使用する。",
  1097. "ストームコーザーが獲物を取った後調理をしている。このイベントが発生するとモンスターは消滅する。「こんなところで人間に会うなんて珍しいな、お前らも食っていくか?」10GPを支払うことでマジカルクッキング#{getRandomDiff(dice1, 64, d, 0)}の効果を得ることができる。",
  1098. "高山植物の群生地。#{getRandomDiff(dice1, 65, d, 0)}のいずれかで判定を行う。成功した場合、「深度×#{getRandomDiff(dice1, 65, d, 1)}」GP相当の薬草が入手可能。",
  1099. "岩壁が大きく崩れる!崩落に巻き込まれ深度が0になってしまう。#{getRandomDiff(dice1, 66, d, 0)}に成功すると何やら崩れたあとに鈍く輝く武器を発見する。武器、盾、鎧の中から好きなもの1つを入手することができる(#{getRandomDiff(dice1, 66, d, 1)}GPまで)",
  1100. ]
  1101. else: 0 else
  1102. table = nil
  1103. end
  1104. when: 0 when 4
  1105. area = "水辺"
  1106. case dice2
  1107. when: 0 when 1
  1108. table = [
  1109. "回復の泉。PC全員のHP・MP・FPが完全に回復する。気絶・朦朧状態も回復。",
  1110. "甲羅干しに適した暖かい小島を見つける。FPとMPを#{getRandomDiff(dice1, 12, d, 0)}回復。ワイズマンは回復量2倍。",
  1111. "魚の群れを発見する。行動を消費して<釣り>に成功すると、さらに行動ターンで<調理>判定を行うことでジャンル「魚」のマジカルクッキングを行うことができる。<釣り>と<調理>を行うキャラクターは別々でも構わない。できた料理の効果はその場で適用する。",
  1112. "ミントや菖蒲を育てているフラウに出会う。100GP払うと薬湯に入れてもらうことができる。FPとMPが生命力と同じ値だけ回復する。",
  1113. "リザードの集落につく。HPの減ったキャラクターがいれば持て囃され、マジカルクッキング「カリカリミミズ肉」をごちそうしてもらい、この先の道案内も買って出てくれる。そのラウンドの深度判定に+3のボーナスを得る。全員のHPが満タンの場合は、そっけない扱いをされ何も起こらない。",
  1114. "回復の泉に見せかけた毒の泉。パーティーメンバーのHP・MP・FPのいずれかが減少している場合このイベントは拒否できない。毒の水でHP・MP・FPに#{getRandomDiff(dice1, 16, d, 0)}のダメージを受ける。HP・MP・FPが全快のキャラクターはこの効果を受けない。#{getRandomDiff(dice1, 16, d, 1)}か「第六感」に成功すればこれが毒の泉だとわかる。",
  1115. ]
  1116. when: 0 when 2
  1117. table = [
  1118. "財宝(カギ・トラップなし)。財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1119. "財宝(カギつき。行動を消費して#{getRandomDiff(dice1, 22, d, 0)}に成功すれば開く)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1120. "財宝(カギなし、トラップつき。行動を消費して#{getRandomDiff(dice1, 23, d, 0)}に成功すれば解除可能)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1121. "財宝(カギ、トラップつき。行動を消費して#{getRandomDiff(dice1, 24, d, 0)}に成功すれば解除可能)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1122. "ミミックの罠。ランダムなキャラクターに3Dの「切り」ダメージを与える。#{getRandomDiff(dice1, 25, d, 0)}に成功すればこの罠を見抜いて無効化することができ、なおかつ「深度×#{getRandomDiff(dice1, 25, d, 1)}」GPを入手可能。",
  1123. "トレジャーイーターの罠。冒険中に入手したアイテム(消耗品・GP以外)を全て失う。#{getRandomDiff(dice1, 26, d, 0)}に成功すればこの罠を見抜いて無効化することができる。",
  1124. ]
  1125. when: 0 when 3
  1126. table = [
  1127. "進みやすい浅瀬だ。深度が1D増加する。#{getRandomDiff(dice1, 31, d, 0)}に成功すればちょうどいいイカダを組み、深度が2D増加。",
  1128. "様々な漂流物が流れ込む船の墓場。障害物が多く進みにくい。#{getRandomDiff(dice1, 32, d, 0)}の判定に成功すれば深度が1D増加。失敗した場合深度が1D減少する。",
  1129. "大蓮のような植物の群生地。荷重レベルが「軽荷」以下のキャラクターがいる場合安全に移動できるようになり深度が1D増加する。全員「並荷」以上の場合は大蓮が絡まり深度が1D減少する。",
  1130. "周囲に深い霧が発生する。#{getRandomDiff(dice1, 34, d, 0)}の判定に失敗すると深度が1D減少する。「暗視」があれば「視覚-2」で判定可能。「方向感覚」があればまったく影響を受けない。",
  1131. "沼地で思うように進めない。#{getRandomDiff(dice1, 35, d, 0)}で判定を行い、失敗すると深度が1D減少する。ペット「スワンプランナー」を装備している場合と【ミズグモ】がある場合はまったく影響を受けない。",
  1132. "水流が複雑になっており思うように進めず戻されてしまう。#{getRandomDiff(dice1, 36, d, 0)}の判定に失敗すると深度が2D減少する。リザードかワイズマンは知力そのままで判定してもよい。",
  1133. ]
  1134. when: 0 when 4
  1135. table = [
  1136. "#{getRandomDiff(dice1, 41, d, 0)}とエンカウント。2ラウンド経過するとキャンディークラウンは戦場全域に《べたべた》をかけて逃亡する。",
  1137. "アシガル潜水隊と遭遇。#{getRandomDiff(dice1, 42, d, 0)}とエンカウント。<偽装>か「視覚-3」判定に成功すると水面に動く竹筒を発見可能。最初の判定に成功していればPC側のイニシアチブ値+1、失敗していれば敵の先手で戦闘を開始する。その際PC先手で進行中の場合もモンスター先手に変更される。",
  1138. "何か水面が揺れている。#{getRandomDiff(dice1, 43, d, 0)}。敵は全員【ハイドインシャドウ】状態。#{getRandomDiff(dice1, 43, d, 1)}判定に失敗すると敵の先手で戦闘を開始する。その際PC先手で進行中の場合もモンスター先手に変更される。",
  1139. "水辺で花を育てている少女に出会う・・・が、少女は#{getRandomDiff(dice1, 44, d, 0)}だった!彼女が育てている花の根本には無数の動物の死体が無残にも肥料にされている。遭遇したラウンドのイニシアチブ判定直後に恐怖判定を行うこと。",
  1140. "水かと思ったらスライムだった!?#{getRandomDiff(dice1, 45, d, 0)}。相手側のイニシアチブ判定には+3のボーナスがある。",
  1141. "高波にのった騎士が現れる。#{getRandomDiff(dice1, 46, d, 0)}。最初の攻撃に限り、【チャージアタック】時に追加で5ヘクス移動した扱いになる。",
  1142. ]
  1143. when: 0 when 5
  1144. table = [
  1145. "美しい歌声が響き渡る、意識が引きずり込まれそうだ。その場にいる全員(敵も)は#{getRandomDiff(dice1, 51, d, 0)}判定を行う。音量自動補正装置がある場合この効果を受けない。失敗した場合1ラウンド朦朧状態となる。朦朧としたキャラクターは深度判定も不可。",
  1146. "小舟で進んでいると、なにやら激しい水の音がする。この先は滝のようだ!行動を消費して#{getRandomDiff(dice1, 52, d, 0)}を行い、全員が失敗すると#{getRandomDiff(dice1, 52, d, 1)}の防護点無視ダメージを受ける。この判定がクリティカルだった場合、滝の裏に財宝の洞窟を発見する。罠や鍵はかかっておらず、財宝の中身は1段階高い深度の財宝テーブルを使用する。",
  1147. "船の墓場だ。強風でマストが倒れてくる。#{getRandomDiff(dice1, 53, d, 0)}に失敗したPCは#{getRandomDiff(dice1, 53, d, 1)}の「叩き」ダメージを受けて転倒する。",
  1148. "水がしょっぱい、ここは塩水のようだ。ミスリル製とアダマン製以外の金属鎧を身に着けている場合、#{getRandomDiff(dice1, 54, d, 0)}の判定に失敗すると防具の防護点#{getRandomDiff(dice1, 54, d, 1)}。下がった防護点は「簡易修理キット」などで修理は可能。ドライブギアの場合、シナリオ終了時にメンテナンスのため(受動防御+防護点)×50GPの費用がかかる。",
  1149. "ここの水は冷たい、気をつけないと体力を奪われてしまう。#{getRandomDiff(dice1, 55, d, 0)}判定を行い、失敗するとFPに#{getRandomDiff(dice1, 55, d, 1)}のダメージを受ける。リザードとワイズマンは生命力判定に-3のペナルティを受ける。",
  1150. "凄まじい勢いで間欠泉が噴き出している!#{getRandomDiff(dice1, 56, d, 0)}の判定に失敗すると。ランダムで1D人が間欠泉に直撃して、#{getRandomDiff(dice1, 56, d, 1)}の「叩き」ダメージを受ける。",
  1151. ]
  1152. when: 0 when 6
  1153. table = [
  1154. "傷付いて荒ぶった#{getRandomDiff(dice1, 61, d, 0)}を発見する。反応判定を行い(「動物共感」なら+4)13以上が出た場合、#{getRandomDiff(dice1, 61, d, 0)}はおとなしくなる。そのあと#{getRandomDiff(dice1, 61, d, 1)}の判定に成功すると、#{getRandomDiff(dice1, 61, d, 0)}がなつき、#{getRandomDiff(dice1, 61, d, 0)}(ペット)を手に入れることができる。反応判定が10~12の場合特に何もおこらない。反応判定が9以下だった場合、#{getRandomDiff(dice1, 61, d, 0)}が暴れてPC全員が1Dの防護点無視ダメージを受け、#{getRandomDiff(dice1, 61, d, 0)}は逃亡する。",
  1155. "なにやら派手な魚を見つける、あれはもしやアズマに伝わる幻の魚「ニシキゴイ」か!?行動を消費して#{getRandomDiff(dice1, 62, d, 0)}の判定に成功すると見事つり上げ、持ち帰ると#{getRandomDiff(dice1, 62, d, 1)}GPとなる。判定にファンブルすると逃げられ、以後判定できなくなる。撤退・全滅した場合ニシキゴイは消滅する。",
  1156. "カエルの合唱が響き渡る。何やら意味がある歌声に聞こえるが・・・#{getRandomDiff(dice1, 63, d, 0)}の判定に成功すると歌の意味を理解できる。「動物共感」があればこの判定に+4のボーナスを得る。カエル達は安全な道を教えてくれていたのだ。判定に成功した場合深度が2D増加する。判定に失敗すると毒の沼に足を踏み入れ、PC全員が#{getRandomDiff(dice1, 63, d, 1)}の防護点無視ダメージを受ける。",
  1157. "老齢のグラントが岩に腰かけ釣りをしている。このイベントが発生するとモンスターは消滅する。「どうだね、よかったら釣り勝負をやっていかないか?グラントの太公望(#{getRandomDiff(dice1, 64, d, 0)})とPCの<釣り>技能で行動を消費して即決勝負を行う。成功度で勝利した場合、「見事じゃ、そこにあるガラクタはワシには必要ない物じゃから好きに持っていくがいい」と財宝を渡してくれる。財宝の中身は1段階高い深度の財宝テーブルを使用する。",
  1158. "船の墓場だ、ここは何かありそうな感じがする。#{getRandomDiff(dice1, 65, d, 0)}に成功すると「2D×#{getRandomDiff(dice1, 65, d, 1)}」GPを入手できる。判定がクリティカルだった場合、それに加えて財宝も入手可能。財宝の中身は1段階高い深度の財宝テーブルを使用する。",
  1159. "貝の群生地だ。#{getRandomDiff(dice1, 66, d, 0)}に成功すると真珠が見つかる。行動を消費して<水泳-4>か<潜水>を行い、1人成功するごとに#{getRandomDiff(dice1, 66, d, 1)}GPを入手可能。水泳や潜水の判定に失敗した場合はFPに1点のダメージを受ける。",
  1160. ]
  1161. else: 0 else
  1162. table = nil
  1163. end
  1164. when: 0 when 5
  1165. area = "森林"
  1166. case dice2
  1167. when: 0 when 1
  1168. table = [
  1169. "回復の泉。PC全員のHP・MP・FPが完全に回復する。気絶・朦朧状態も回復。",
  1170. "鬱蒼とした森の奥に見事な佇まいの茶室を見つける。【ソチャデスガ】を使用した際の回復量が2倍になる。パーティーにサスライがいない場合は友好的なカラクリフラウ(CL6)がいて、「PTの人数×20」GPで<茶道15>の【ソチャデスガ】を使用してくれる。",
  1171. "おいしそうな果実を見つける。<植物学>か<動植物知識-3>で判定を行い、成功するとHPとFPが#{getRandomDiff(dice1, 13, d, 0)}回復する。",
  1172. "果実を育てているフラウに出会う。「PTの人数×20」GP払うとジャンル「果実」のマジカルクッキングを行うことができる。品質が良いので<調理>には+2のボーナスを得る。できた料理の効果はその場で適用する。",
  1173. "森の中にひっそりとたたずむジンジャを発見して、ナインテイルのカンヌシかミコが旅の無事を祈ってくれる。パーティー全員に【不死なる炎+5】がかかり、最終イベントに入るまで、死亡判定に自動的に成功するようになる。この効果が続いている間、保険を適用した状態で死亡判定に突入しても帰還せずにその戦闘を継続することが可能。",
  1174. "食人植物の花粉による回復の泉の幻影。パーティーメンバーのHP・MP・FPのいずれかが減少している場合このイベントは拒否できない。パーティーの誰かが#{getRandomDiff(dice1, 16, d, 0)}に成功しない限り食人植物の群生地にふらふらと入ってしまい、全員が#{getRandomDiff(dice1, 16, d, 1)}の「切り」ダメージを受ける。パーティーにフラウがいれば事前に気が付きダメージは受けない",
  1175. ]
  1176. when: 0 when 2
  1177. table = [
  1178. "財宝(カギ・トラップなし)。財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1179. "財宝(カギつき。行動を消費して#{getRandomDiff(dice1, 22, d, 0)}に成功すれば開く)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1180. "財宝(カギなし、トラップつき。行動を消費して#{getRandomDiff(dice1, 23, d, 0)}に成功すれば解除可能)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1181. "財宝(カギ、トラップつき。行動を消費して#{getRandomDiff(dice1, 24, d, 0)}に成功すれば解除可能)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1182. "ミミックの罠。ランダムなキャラクターに3Dの「切り」ダメージを与える。#{getRandomDiff(dice1, 25, d, 0)}に成功すればこの罠を見抜いて無効化することができ、なおかつ「深度×#{getRandomDiff(dice1, 25, d, 1)}」GPを入手可能。",
  1183. "トレジャーイーターの罠。冒険中に入手したアイテム(消耗品・GP以外)を全て失う。#{getRandomDiff(dice1, 26, d, 0)}に成功すればこの罠を見抜いて無効化することができる。",
  1184. ]
  1185. when: 0 when 3
  1186. table = [
  1187. "#{getRandomDiff(dice1, 31, d, 0)}に成功すれば獣道を発見し深度が2D増加する。「動物共感」があれば判定不要。",
  1188. "複雑で迷いそうな密林に迷い込んでしまう。鳥たちが古い言葉の会話を鳴声で再現しており、#{getRandomDiff(dice1, 32, d, 0)}に成功するとこの森について秘密がわかり深度が1D増加する。失敗した場合道に迷い進行度が1D減少する。",
  1189. "兎たちがこちらを伺っている。「動物共感」があれば道案内をしてくれ、深度が1D増加する。この時マジカルクッキングで作ったものが「キャロットタルト」だった場合は「動物共感」があるのと同じように深度が1D増加するうえ、以後ラウンド開始時にずっとこの効果を得ることができる。",
  1190. "毒草の群生地だ。直進すると進行度が1D増加するが、#{getRandomDiff(dice1, 34, d, 0)}判定に失敗するとHPとFPに#{getRandomDiff(dice1, 34, d, 1)}の防護点無視ダメージを受ける。遠回りする場合、進行度が1D減少する。",
  1191. "背の高い草が生い茂っており、岩も多く進みづらい、飛行を能力を持ったPCが先の様子を確認しない限り、移動に手間取り進行度が2D減少する。ペット「スカイサーチャー」や魔法《飛行》《魔法の目》でも確認可能。",
  1192. "森林火災に遭遇する、進行方向から動物たちが逃げ出していくのが見える。迂回して安全策を通るなら進行度が2D減少する。このまま進む場合シナリオ終了までラウンド開始時に炎により#{getRandomDiff(dice1, 36, d, 0)}の「叩き」ダメージを受ける。",
  1193. ]
  1194. when: 0 when 4
  1195. table = [
  1196. "#{getRandomDiff(dice1, 41, d, 0)}とエンカウント。2ラウンド経過するとキャンディークラウンは戦場全域に《べたべた》をかけて逃亡する。",
  1197. "動物狩りを楽しんでいた魔族と偶然遭遇してしまう。#{getRandomDiff(dice1, 42, d, 0)}とエンカウント。#{getRandomDiff(dice1, 42, d, 1)}には全員《ぼやけ5》がかかった状態。#{getRandomDiff(dice1, 42, d, 2)}減らしておくこと。",
  1198. "魔族の偵察隊と遭遇する。#{getRandomDiff(dice1, 43, d, 0)}とエンカウント。オウルセージのうち1体は行動ターンに逃亡して他の魔族に警戒を呼び掛けに行く。これを阻止できなかった場合、以後出現する「分類:魔族」のモンスターは物理攻撃の致傷力+#{getRandomDiff(dice1, 43, d, 1)}、防護点+#{getRandomDiff(dice1, 43, d, 1)}のボーナスを得る。",
  1199. "木々の間を飛び回る何かに背後から突然襲撃される。#{getRandomDiff(dice1, 44, d, 0)}。ペット「スカイサーチャー」か「広視界」がなければ必ず相手の先制攻撃になり、その際PC先手で進行中の場合もモンスター先手に変更される。",
  1200. "果物を採取する少女達を発見する。しかしよく見ると血塗れの鋏を持つ人形だった!#{getRandomDiff(dice1, 45, d, 0)}とエンカウント。パーティーメンバー全員が#{getRandomDiff(dice1, 45, d, 1)}で判定を行い、成功すれば回避可能。",
  1201. "前方の森に何か違和感を感じる。周囲に擬態していた#{getRandomDiff(dice1, 46, d, 0)}。「視覚-5」か「第六感」の判定に成功していなければ必ず相手の先制攻撃になり、その際PC先手で進行中の場合もモンスター先手に変更される。判定成功時は深度を1D減少させて戦闘回避も可能。",
  1202. ]
  1203. when: 0 when 5
  1204. table = [
  1205. "良い香りが周囲に満ちていく。闘争心を失わせるキノコの香りで、戦闘中だった場合敵味方ともに剣を収め強制的に戦闘終了となる。また、以後シナリオ終了まで「平和愛好:専守防衛」の特徴を得る。(意志判定に失敗するとイニシアチブ判定に自動敗北)この効果を受けたくない場合、#{getRandomDiff(dice1, 51, d, 0)}のいずれかの判定に成功する必要がある。この判定には「鋭敏味覚」のレベル分ボーナスを得る。",
  1206. "美味しそうな果実が生っているのを見つける。意志判定に失敗するとすぐに食べてしまうが(「グルメ」の場合「意志-3」)興奮作用のある実のため頭に血が昇ってしまう。HPとFPが#{getRandomDiff(dice1, 52, d, 0)}回復するが「バーサーク」の特徴を得る。",
  1207. "巧妙なベアトラップが仕掛けてある。ランダムなキャラクター1人(モンスターも含む)に#{getRandomDiff(dice1, 53, d, 0)}の「切り」ダメージを与える。以後ターンの最初に#{getRandomDiff(dice1, 53, d, 1)}の判定に成功するまで移動不可。本人か隣接したキャラクターが行動を消費して#{getRandomDiff(dice1, 53, d, 2)}で判定することでも解除可能。",
  1208. "突然のスコールに見舞われる。#{getRandomDiff(dice1, 54, d, 0)}判定を行い、失敗すると体温が奪われFPに#{getRandomDiff(dice1, 54, d, 1)}のダメージを受ける。リザードとワイズマンはこの効果を受けない。<気象学-3>に成功すればあらかじめ雨宿りができ、この効果を受けない。森林イベント3-6の山火事が起きていた場合、その効果は消滅する。",
  1209. "巨大食虫植物の群生地に足を踏み入れてしまう。#{getRandomDiff(dice1, 55, d, 0)}で判定を行い、失敗するとランダムで1人が植物に飲み込まれてしまう。強酸により#{getRandomDiff(dice1, 55, d, 1)}の「叩き」ダメージを受け、金属でない鎧を装備していた場合1Dで1、2が出ると破壊される。",
  1210. "すさまじい悪臭を放つ巨大な花。#{getRandomDiff(dice1, 56, d, 0)}判定に失敗したキャラクターはシナリオ終了まで知力が#{getRandomDiff(dice1, 56, d, 1)}点減少する(最大MPは変化しないものとする)また、対応技能が<技師/魔道具>以外のペットは匂いで気絶してシナリオ終了まで効果を得られなくなる。",
  1211. ]
  1212. when: 0 when 6
  1213. table = [
  1214. "魔族の狩りにより深く傷ついたクレッセントムーンを発見する。<応急処置-7>か<獣医-3>の判定に成功すると、クレッセントムーンの傷は完治し、クレッセントムーン(ペット)を手に入れることができる。",
  1215. "少し開けた原っぱで、フラウのダンスパーティーに誘われる。このイベントが発生するとモンスターは消滅する#{getRandomDiff(dice1, 62, d, 0)}で判定を行い、成功するとそこにキノコが生え始める。フラウは協力してくれたお礼にこのキノコを分けてくれる。大変貴重な珍味で、持ち帰ると「(1D+成功度)×#{getRandomDiff(dice1, 62, d, 1)}」GPになる。",
  1216. "フラウたちが「森ガールファッションコンテスト」を開催しており、その助っ人を依頼される。このイベントが発生するとモンスターは消滅する。#{getRandomDiff(dice1, 63, d, 0)}に成功すると自然と一体化したファッションが高評価を受け、お礼に#{getRandomDiff(dice1, 63, d, 1)}(装飾品)を入手できる。",
  1217. "霊樹の花にたまった水が魔力を帯びている。<神秘学>に成功するとそれにポーションとしての効果があることが分かる。1Dを振り、その出目に対応したポーションが手に入る。
  1218. ----------
  1219. #{getRandomDiff(dice1, 64, d, 0)}
  1220. ----------",
  1221. "迷子のフラウを見つける。イベント表で他のフラウに出会った場合そのフラウと知り合いで、お礼に財宝を渡してくれる。財宝の中身は1段階高い深度の財宝テーブルを使用する。フラウに出会えずシナリオをクリアした場合も、1段階低い深度の財宝テーブルの中身をくれる。",
  1222. "ランダムに選んだPC1人が、うっかり泉に武器を落としてしまう。すると女神が出て落とした武器と同じ技能で扱うもので、価格が一ランク上のアイテムを落としたのかと聞いてくる。落とした武器と提示してきた武器の差額を1000で割った値をペナルティとして意志判定を行うこと。「守銭奴」はペナルティが2倍になるが、「正直」の場合は自動的に成功になる。成功すると正直に答え提示されたアイテムを両方手に入れることができるが、失敗すると嘘をついて女神を怒らせてしまい、武器を失う。落とした武器が10000GP以上だった場合や、それ以上の武器がアイテムリストになかった場合、自動的にアイテムは返却してもらえる。",
  1223. ]
  1224. else: 0 else
  1225. table = nil
  1226. end
  1227. when: 0 when 6
  1228. area = "墓地"
  1229. case dice2
  1230. when: 0 when 1
  1231. table = [
  1232. "回復の泉。PC全員のHP・MP・FPが完全に回復する。気絶・朦朧状態も回復。",
  1233. "アズマ風の墓石が佇んでいる。<地域知識/アズマ><地域知識/カベノナカ-4>のいずれかで判定を行う。成功すると正しくお参りを行うことができ、HP、FP、MPの全てが#{getRandomDiff(dice1, 12, d, 0)}回復する。失敗すると霊を怒らせ、全員がFPに#{getRandomDiff(dice1, 12, d, 1)}のダメージを受ける。",
  1234. "墓守の休憩所を見つける。様々な薬草が置いてあり、行動を消費して<応急処置>を行うことができる。成功すれば#{getRandomDiff(dice1, 13, d, 0)}のHPが回復する。",
  1235. "ヒガンバナの世話をするフラウと出会う。100GPを払うと「ヒガンバナの毒」を武器に塗ってもらうことができる。最終ダメージに+2の効果があり、武器の通じない「ファントム」のようなモンスターにも武器による攻撃が有効になる。この効果はシナリオ終了時まで持続する。",
  1236. "シルヴァテイルのネクロマンサー達が集まって、何やら怪しい儀式をしている。道中で死亡もしくは保険を適用して強制送還されたキャラクターがいれば、#{getRandomDiff(dice1, 15, d, 0)}GPを支払うことで復活させてもらうことができる。それ以外の場合、何か不気味な儀式に不安を感じ、FPを1点消耗する。",
  1237. "回復の泉があるのだが・・・?パーティーメンバーのHP・MP・FPのいずれかが減少している場合このイベントは拒否できない。HP・MP・FPが完全に回復して気絶や朦朧からも立ち直るが、黄泉の国の水を飲んだことで迷宮から出るまで「分類:アンデッド」となる。回復魔法の効果などは通常の効果があるが、一部の技や魔法で特攻を受ける。《閃光》を受けた際も3Dの防護点無視ダメージを受ける。",
  1238. ]
  1239. when: 0 when 2
  1240. table = [
  1241. "財宝(カギ・トラップなし)。財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1242. "財宝(カギつき。行動を消費して#{getRandomDiff(dice1, 22, d, 0)}に成功すれば開く)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1243. "財宝(カギなし、トラップつき。行動を消費して#{getRandomDiff(dice1, 23, d, 0)}に成功すれば解除可能)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1244. "財宝(カギ、トラップつき。行動を消費して#{getRandomDiff(dice1, 24, d, 0)}に成功すれば解除可能)財宝の中身は1段階低い深度の財宝テーブルを使用する。",
  1245. "ミミックの罠。ランダムなキャラクターに3Dの「切り」ダメージを与える。#{getRandomDiff(dice1, 25, d, 0)}に成功すればこの罠を見抜いて無効化することができ、なおかつ「深度×#{getRandomDiff(dice1, 25, d, 1)}」GPを入手可能。",
  1246. "トレジャーイーターの罠。冒険中に入手したアイテム(消耗品・GP以外)を全て失う。#{getRandomDiff(dice1, 26, d, 0)}に成功すればこの罠を見抜いて無効化することができる。",
  1247. ]
  1248. when: 0 when 3
  1249. table = [
  1250. "なにもなさそうな道だが、#{getRandomDiff(dice1, 31, d, 0)}で判定を行う。成功するとちょっとなにかでそうな近道を発見する。深度が2D増加するが、「臆病」なキャラクターは意志判定が必要。",
  1251. "舗装されていて通りやすい道が続く。深度が1D増加する。途中には祠があり、マジカルクッキングで作った食べ物を持っていた場合、それをお供えすることでHP・MP・FPが全回復する。",
  1252. "道が途切れ、草が伸び放題の荒れ地に出る。進むには骨が折れそうだ。#{getRandomDiff(dice1, 33, d, 0)}に成功すれば深度+2。失敗するとFPに#{getRandomDiff(dice1, 33, d, 1)}点のダメージを受ける。",
  1253. "どこまでも卒塔婆とススキしかない・・・同じ景色が続き進んでいるか怪しくなる。2分の1の確率で深度が1D減少する。「方向感覚」があればこの効果は無視できる。",
  1254. "地面から突如骨の手が伸び移動を邪魔する。全員「移動力+5」を目標値に判定を行い、失敗したキャラクターの人数だけ深度が減少する。【死者に鞭】を持つネクロマンサーがいればこの効果は無視できる。",
  1255. "先へ進む道には死者の呪いが満ちている。そのまま進むと深度が1D増加するが、以後全ての判定の目標値に#{getRandomDiff(dice1, 36, d, 0)}のペナルティを受ける。遠回りをすると悪影響は受けないが深度が1D減少する。【死者に鞭】を持つネクロマンサーがいれば直進しても悪影響を受けない。",
  1256. ]
  1257. when: 0 when 4
  1258. table = [
  1259. "#{getRandomDiff(dice1, 41, d, 0)}とエンカウント。2ラウンド経過するとキャンディークラウンは戦場全域に《べたべた》をかけて逃亡する。",
  1260. "朽ちていた骨が突如起き上がり襲いかかる。#{getRandomDiff(dice1, 42, d, 0)}。「第六感」の判定に成功していなければ必ず相手の先制攻撃になり、その際PC先手で進行中の場合もモンスター先手に変更される。",
  1261. "不吉な歌を口すざみ、ステップを踏みながらかわいらしい少女が近づいてくる。#{getRandomDiff(dice1, 43, d, 0)}とエンカウント。#{getRandomDiff(dice1, 43, d, 1)}の「華劇」は最初から#{getRandomDiff(dice1, 43, d, 2)}段階進行している。",
  1262. "遠くから不吉な進軍の音を聞く。PCは全員「聴覚-4」か「第六感」で判定を行うこと。ネクロマンサーは知力判定を行ってもよい。誰か1人でも判定に成功すれば、魔将グレイヴディガーの軍勢が迫っているのを知り、深度を1D減少させてひとまず逃亡することができる。全員判定に失敗してしまうとPCは魔将グレイヴディガー(CL200)とその配下である無数の亡霊騎士団と相対することになる。#{getRandomDiff(dice1, 44, d, 0)}",
  1263. "貴族の棺とそれを守る人形。#{getRandomDiff(dice1, 45, d, 0)}とエンカウント。棺の中には貴金属が入っており、#{getRandomDiff(dice1, 45, d, 1)}を倒せば「深度×#{getRandomDiff(dice1, 45, d, 2)}」GPを入手可能。",
  1264. "壁に埋まった10mはあろうかという巨大な蛇の骨が、動き出し襲いかかってくる。#{getRandomDiff(dice1, 46, d, 0)}。",
  1265. ]
  1266. when: 0 when 5
  1267. table = [
  1268. "PC全員に墓から突然幻影が襲いかかる。#{getRandomDiff(dice1, 51, d, 0)}判定に失敗すると気を取られ「受け」か「止め」を1回消費する。「受け」も「止め」も行えない場合腰を抜かして転倒してしまう。",
  1269. "ギロチンが突如PCのうちランダムに1人に目掛けて落ちてくる。盾の受動防御を無視した#{getRandomDiff(dice1, 52, d, 0)}に失敗すると#{getRandomDiff(dice1, 52, d, 1)}の「切り」ダメージを受ける。",
  1270. "用途不明の建物に迷い込む。#{getRandomDiff(dice1, 53, d, 0)}に成功すると、その建物が火葬場であると判明し、すぐに脱出できる。判定に失敗するとPC全員が火炎で#{getRandomDiff(dice1, 53, d, 1)}の「叩き」ダメージを受ける。",
  1271. "墓石が動き出し中から何かが出てこようとしている。行動を消費して#{getRandomDiff(dice1, 54, d, 0)}で判定を行い、成功すればなにも起こらない。失敗した場合、探索中に倒されたモンスターの中で最もCLが高いモンスターと再度エンカウントする(深度判定終了後)該当するモンスターが存在しなかった場合、#{getRandomDiff(dice1, 54, d, 1)}が出現する。",
  1272. "金の亡者が群がってくる。「2D×#{getRandomDiff(dice1, 55, d, 0)}」GPを払うと支払うと満足して去っていくが、支払を拒否した場合はPC全員が#{getRandomDiff(dice1, 55, d, 1)}の「叩き」ダメージを受ける。【死者に鞭】を持つネクロマンサーがいればこの効果は無視できる。",
  1273. "ランダムなPC1人の武器が死者の怨念を吸い取り魔剣となる。魔剣は致傷力に+2のボーナスを得るが、所有者は最大HPが5点減少し、不利な特徴「バーサーク」「残忍」を持つようになる。魔剣には「マジックパウダー:無」が常にかかっているものとみなす。魔剣となった武器は売却不可能で、不要な場合捨てるしかない。すでに魔剣になっている武器と、グラントの宝剣は魔剣にはならない。",
  1274. ]
  1275. when: 0 when 6
  1276. table = [
  1277. "雷が突然鳴り響く。その場にいる全てのキャラクター(モンスター含む)は全員3Dを振り、金属鎧を着ているキャラクターはその値に+3する。この値が一番高いキャラクターは電撃により#{getRandomDiff(dice1, 61, d, 0)}の「叩き」ダメージを受ける(金属鎧の防護点を無視)",
  1278. "タルの上に腰かけ酒を口に運び続ける、減ることのない酒に向き合うスケルトンがいる。「どうだ、お前らも飲んでいくか?」と声をかけられる。酒を飲む場合、#{getRandomDiff(dice1, 62, d, 0)}判定を4回連続で行うこと。全て成功した場合は、「ついに酒が切れたか、最後の晩酌に付き合ってもらって感謝する」と感謝を述べて財宝を渡してくれる。財宝の中身は1段階高い深度の財宝テーブルを使用する。途中で1度でも失敗した場合、酒に悪酔いしてシナリオ終了まで全ての判定に-1のペナルティを受ける。",
  1279. "妖しい輝きを放つ宝石を発見する。手にとると呪われてシナリオ終了まで全ての判定に#{getRandomDiff(dice1, 63, d, 0)}のペナルティを受ける。手にとらない場合は意志判定に成功しなければならず、「守銭奴」「好奇心」「直情」がある場合意志判定に-3のペナルティを受ける(不利な特徴が複数ある場合修正は累積する)無事持ち帰った場合呪いは解け、#{getRandomDiff(dice1, 63, d, 1)}GPで売却できる",
  1280. "朽ちたギアの墓場。まだ使えるギアがあるかもしれない。<技師/魔道具>の判定を行い、5成功以上ならアイテムが入手可能。アイテムの内容は1Dで決定する。
  1281. ----------
  1282. #{getRandomDiff(dice1, 64, d, 0)}
  1283. ----------",
  1284. "うすら寒い気配の漂う川辺に出る。川辺には渡し守らしき、ローブをかぶった2人の少女がいる。1人あたり#{getRandomDiff(dice1, 65, d, 0)}GPを支払えば深度が1D増加する。支払を拒否した場合は#{getRandomDiff(dice1, 65, d, 1)}。",
  1285. "『千ノ戦イデ千ノ勝チ方ヲ知ル者、ココニ眠ル』と刻まれた棺を見つける。「好奇心」「直情」のキャラクターは開けずにいるには意志判定が必要。棺を開けた場合は#{getRandomDiff(dice1, 66, d, 0)}。勝利した場合、通常のドロップとは別に#{getRandomDiff(dice1, 66, d, 1)}(《戻る武器》は無し)が必ず手に入る。
  1286. ----------
  1287. #{getRandomDiff(dice1, 66, d, 2)}
  1288. ----------",
  1289. ]
  1290. else: 0 else
  1291. table = nil
  1292. end
  1293. else: 0 else
  1294. return nil
  1295. end
  1296. 2 return area, dif, table
  1297. end
  1298. 1 def getRandomDiff(dice1, dice23, dif, index)
  1299. 16 table = []
  1300. 16 case dice1
  1301. when: 11 when 1 # 洞窟
  1302. table = [
  1303. 11 [12, [
  1304. ['1', '2', '3', '4']
  1305. ]],
  1306. [13, [
  1307. ['<植物学>か<動植物知識-3>', '<植物学-2>か<動植物知識-5>', '<植物学-4>か<動植物知識-7>', '<植物学-8>か<動植物知識-11>'],
  1308. ['5', '10', '15', '20'],
  1309. ]],
  1310. [22, [
  1311. ['<鍵開け-3>', '<鍵開け-5>', '<鍵開け-7>', '<鍵開け-11>']
  1312. ]],
  1313. [23, [
  1314. ['<罠-3>', '<罠-5>', '<罠-7>', '<罠-11>']
  1315. ]],
  1316. [24, [
  1317. ['<罠-3><鍵開け-3>', '<罠-5><鍵開け-5>', '<罠-7><鍵開け-7>', '<罠-11><鍵開け-11>']
  1318. ]],
  1319. [25, [
  1320. ['<罠-5>', '<罠-5>', '<罠-7>', '<罠-11>'],
  1321. ['100', '200', '300', '500'],
  1322. ]],
  1323. [26, [
  1324. ['<罠-5>', '<罠-5>', '<罠-7>', '<罠-11>']
  1325. ]],
  1326. [34, [
  1327. ['<軽業>', '<軽業-2>', '<軽業-4>', '<軽業-8>'],
  1328. ['3D', '4D', '6D', '10D'],
  1329. ]],
  1330. [35, [
  1331. ['HP30', 'HP60', 'HP90', 'HP150']
  1332. ]],
  1333. [36, [
  1334. ['「知力-1」', '「知力-2」', '「知力-3」', '「知力-5」']
  1335. ]],
  1336. [41, [
  1337. ['キャンディークラウン(CL40)', 'キャンディークラウン(CL40)「1D-3」匹(最低1匹)', 'キャンディークラウン(CL40)「1D-2」匹(最低1匹)、出目が6だった場合ゴールデンクラウン(CL177)1匹', 'ゴールデンクラウン(CL177)']
  1338. ]],
  1339. [42, [
  1340. ['ベルセルク(CL7)×3とエンカウント。', 'ベルセルク(CL7)×3とエンカウント。', 'ベルセルク(CL15)×3とエンカウント、命中+10、ST24、HP+40、FP+8。', 'ベルセルク(CL25)×3とエンカウント、命中+20、ST32、HP+90、FP+18。'],
  1341. ['争っていたためHPとFPは半減している', '', '', ''],
  1342. ]],
  1343. [43, [
  1344. ['ロックバトラー(CL6)×3とエンカウント。', 'ガーゴイル(CL10)×3とエンカウント、【ハイドインシャドウ】を追加。', 'ガーゴイル(CL15)×3とエンカウント、以下のように強化。', 'ザッハーク(CL39)×2とエンカウント。'],
  1345. ['', '', '
  1346. ----------
  1347. ガーゴイル(CL15) 魔族/岩石
  1348. ST20 DX13 IQ13 HT18 HP63 FP33
  1349. 受防3 防護18 移動6(飛行) よけ6 受け8 止め-
  1350. ガーゴイルの戦槌16(両手メイス)・・・命中20 3d+8「叩き」 重量5
  1351. ・ニンジャ
  1352. 【ハイドインシャドウ】
  1353. ・グラント
  1354. 【グランドインペイル+3】【エクステンドインペイル】【トルマリンスパーク+3】
  1355. 【チェーンスパーク】【グラビティブレイク+4】【グラビティパニッシュ】
  1356. ----------', ''],
  1357. ]],
  1358. [44, [
  1359. ['デビルホール(CL18)とエンカウント。', 'デビルホイール(CL22)とエンカウント、防護点+2、HP+12。', 'デビルホイール(CL26)とエンカウント、防護点+4、HP+24。', 'ムスペルヘイムの獣(CL65)とエンカウント。'],
  1360. ['5D', '6D', '8D', '12D'],
  1361. ]],
  1362. [45, [
  1363. ['3D', '4D', '5D', '6D'],
  1364. ['ヘルハウンド(CL12)、インプ(CL3)×2', 'ヘルハウンド(CL12)×2', 'フェニックス(CL25)、ヘルハウンド(CL12)×2', '火龍ヘルブレイザー(CL50)、ケルベロス(CL33)'],
  1365. ]],
  1366. [46, [
  1367. ['1D', '1D+1', '2D', '3D'],
  1368. ['アイスメイデン(CL10)、アイスリザード(CL7)、スノー(CL3)', 'カロン(CL12)×2、アイスメイデン(CL10)', 'クリスタルビースト(CL25)×2', '氷龍グレイシャル(CL65)'],
  1369. ]],
  1370. [52, [
  1371. ['3ヘクス', '5ヘクス', '7ヘクス', '12ヘクス'],
  1372. ['3D', '5D', '7D', '12D'],
  1373. ]],
  1374. [53, [
  1375. ['「生命力-4」', '「生命力-6」', '「生命力-8」', '「生命力-12」']
  1376. ]],
  1377. [54, [
  1378. ['2D', '3D', '5D', '10D']
  1379. ]],
  1380. [55, [
  1381. ['「よけ」', '「よけ-2」', '「よけ-4」', '「よけ-8」'],
  1382. ['5D', '7D', '9D', '15D'],
  1383. ]],
  1384. [61, [
  1385. ['<天文学-5>', '<天文学-5>', '<天文学-7>', '<天文学-11>'],
  1386. ['レア装飾品「星の怒り」かレア魔法《彗星》(好きな方)', 'レア装飾品「星の怒り」かレア魔法《彗星》(好きな方)', 'レア魔法《流星群》', 'レア魔法《滅びの矢》'],
  1387. ]],
  1388. [62, [
  1389. ['2', '3', '4', '5']
  1390. ]],
  1391. [63, [
  1392. ['7', '9', '11', '15']
  1393. ]],
  1394. [64, [
  1395. ['50', '100', '150', '200']
  1396. ]],
  1397. [66, [
  1398. ['《粉砕3》', '《粉砕4》', '《粉砕6》', '《粉砕10》'],
  1399. ['HP30', 'HP60', 'HP90', 'HP150'],
  1400. ]],
  1401. ]
  1402. when: 0 when 2 # 遺跡
  1403. table = [
  1404. [12, [
  1405. ['2D', '3D', '4D', '6D']
  1406. ]],
  1407. [13, [
  1408. ['<錬金術>か<医師-3>', '<錬金術-2>か<医師-5>', '<錬金術-4>か<医師-7>', '<錬金術-8>か<医師-11>']
  1409. ]],
  1410. [16, [
  1411. ['3000GP', '4000GP', '6000GP', '10000GP'],
  1412. ['5000GP', '10000GP', '20000GP', '40000GP'],
  1413. ['8D', '10D', '15D', '20D'],
  1414. ]],
  1415. [22, [
  1416. ['<鍵開け-3>', '<鍵開け-5>', '<鍵開け-7>', '<鍵開け-11>']
  1417. ]],
  1418. [23, [
  1419. ['<罠-3>', '<罠-5>', '<罠-7>', '<罠-11>']
  1420. ]],
  1421. [24, [
  1422. ['<罠-3><鍵開け-3>', '<罠-5><鍵開け-5>', '<罠-7><鍵開け-7>', '<罠-11><鍵開け-11>']
  1423. ]],
  1424. [25, [
  1425. ['<罠-5>', '<罠-5>', '<罠-7>', '<罠-11>'],
  1426. ['100', '200', '300', '500'],
  1427. ]],
  1428. [26, [
  1429. ['<罠-5>', '<罠-5>', '<罠-7>', '<罠-11>']
  1430. ]],
  1431. [31, [
  1432. ['<身振り-3><演技><演劇>', '<身振り-5><演技-2><演劇-2>', '<身振り-7><演技-4><演劇-4>', '<身振り-11><演技-8><演劇-8>'],
  1433. ]],
  1434. [32, [
  1435. ['<モンスター知識-5>か<地域知識/カベノソト-3>', '<モンスター知識-7>か<地域知識/カベノソト-5>', '<モンスター知識-9>か<地域知識/カベノソト-7>', '<モンスター知識-13>か<地域知識/カベノソト-11>'],
  1436. ]],
  1437. [33, [
  1438. ['に等しい', '×2の', '×3の', '×5の'],
  1439. ]],
  1440. [34, [
  1441. ['<登攀>', '<登攀-2>', '<登攀-4>', '<登攀-8>'],
  1442. ]],
  1443. [35, [
  1444. ['「敏捷力」', '「敏捷力-2」', '「敏捷力-4」', '「敏捷力-8」'],
  1445. ['6D', '8D', '10D', '15D'],
  1446. ]],
  1447. [36, [
  1448. ['「知力-5」', '知力-6', '「知力-7」', '「知力-9」'],
  1449. ]],
  1450. [41, [
  1451. ['キャンディークラウン(CL40)', 'キャンディークラウン(CL40)「1D-3」匹(最低1匹)', 'キャンディークラウン(CL40)「1D-2」匹(最低1匹)、出目が6だった場合ゴールデンクラウン(CL177)1匹', 'ゴールデンクラウン(CL177)']
  1452. ]],
  1453. [42, [
  1454. ['ガーゴイル(CL10)とエンカウント', 'ガーゴイル(CL15)とエンカウント、以下のように強化', 'ザッハーク(CL39)とエンカウント', 'ラダマンティスの蛇(CL50)×2とエンカウント、必ず敵の先制攻撃'],
  1455. ['', '
  1456. ----------
  1457. ガーゴイル(CL15) 魔族/岩石
  1458. ST20 DX13 IQ13 HT18 HP63 FP33
  1459. 受防3 防護18 移動6(飛行) よけ6 受け8 止め-
  1460. 宝石への命中判定ペナルティは-10
  1461. ガーゴイルの戦槌16(両手メイス)・・・命中20 3d+8「叩き」 重量5
  1462. ・ニンジャ
  1463. 行動:【ハイドインシャドウ】 FP1 姿を消す 「視覚-5」で発見可能
  1464. ・グラント
  1465. 行動:【グランドインペイル+3】+【エクステンドインペイル+1】(両手メイス) FP10
  1466. 3D+8「叩き」 受動防御無視「よけ」のみ 半径3ヘクス攻撃 射程5
  1467. 行動:【トルマリンスパーク+2】+【チェーンスパーク】(両手メイス) FP7
  1468. 3D+8「叩き」 命中もしくは「受け」「止め」時に電撃で2D+2の追加ダメージ
  1469. 行動:【グラビティブレイク+2】+【グラビティパニッシュ】(両手メイス) FP7
  1470. 3D+13「叩き」 「荷重レベル+3」の回避ペナルティ 命中後1ターンペナルティ持続
  1471. ----------', '', ''],
  1472. ]],
  1473. [43, [
  1474. ['スターゲイザー(CL10)、ウイングシレイブ(CL4)', 'スターゲイザー(CL10)×2、ポイズンリリー(CL7)', 'コスモロジスト(CL20)×2、オウルコマンダー(CL18)', '栄光の天使(CL60)、ヴァルキリー(CL20)×2'],
  1475. ]],
  1476. [44, [
  1477. ['<文学>か<礼儀作法-3>', '<文学-3>か<礼儀作法-6>', '<文学-6>か<礼儀作法-9>', '<文学-12>か<礼儀作法-15>'],
  1478. ['ヤシャ(CL10)、スケルトン(CL3)×2', 'ヤシャ(CL15、ST17、HP43、FP28、命中22に強化)、ゴースト(CL10)×2', 'ヤシャ(CL25、ST23、HP63、FP38、命中30に強化)、カロン(CL12)×2', 'コンゴウ(CL60)×2'],
  1479. ]],
  1480. [45, [
  1481. ['ヘルハウンド(CL12)', 'ケルベロス(CL33)', '火龍ヘルブレイザー(CL50)', '煉獄龍バーガトリ(CL100)'],
  1482. ]],
  1483. [46, [
  1484. ['ゴーレム(CL12)', 'ミスリルゴーレム(CL27)', 'アダマンゴーレム(CL45)', 'カラクリヒメショウグン(CL75)'],
  1485. ['2D', '3D', '4D', '4D'],
  1486. ]],
  1487. [51, [
  1488. ['「よけ」', '「よけ-2」', '「よけ-4」', '「よけ-8」'],
  1489. ['1D+3', '2D+1', '2d+3', '4D'],
  1490. ['「生命力」', '「生命力-2」', '「生命力-4」', '「生命力-8」'],
  1491. ['1D', '2D', '3D', '5D'],
  1492. ]],
  1493. [52, [
  1494. ['「生命力-3」', '「生命力-5」', '「生命力-7」', '「生命力-11」'],
  1495. ]],
  1496. [53, [
  1497. ['HPを2倍に計算しCLは10とする', 'HPを3倍に計算しCLは15とする', 'HPを4倍に計算しCLは20とする', 'HPを6倍に計算しCLは30とする'],
  1498. ]],
  1499. [54, [
  1500. ['「意志」', '「意志-2」', '「意志-4」', '「意志-8」'],
  1501. ]],
  1502. [56, [
  1503. ['「現在の深度÷2」以下のCLのモンスター', '「現在の深度」以下のCLのモンスター', '「現在の深度×1.5」以下のCLのモンスター', 'CL80以下のモンスター(ネームド以外)'],
  1504. ]],
  1505. [62, [
  1506. ['6', '7', '8', '10'],
  1507. ['9', '10', '11', '14'],
  1508. ['12', '13', '14', '16'],
  1509. ]],
  1510. [64, [
  1511. ['<医師>か<考古学>', '<医師-2>か<考古学-2>', '<医師-4>か<考古学-4>', '<医師-8>か<考古学-8>'],
  1512. ]],
  1513. [65, [
  1514. ['', '', '、ゴールデンクラウン(CL177)', '、ゴールデンクラウン(CL177)×2'],
  1515. ]],
  1516. [66, [
  1517. ['30', '60', '90', '150'],
  1518. ['「深度÷2」', '「深度」', '「深度×1.5」', '「深度×2」'],
  1519. ]],
  1520. ]
  1521. when: 5 when 3 # 断崖
  1522. table = [
  1523. 5 [12, [
  1524. ['「意志」', '「意志-2」', '「意志-4」', '「意志-7」'],
  1525. ]],
  1526. [13, [
  1527. ['2D', '3D', '4D', '6D'],
  1528. ]],
  1529. [14, [
  1530. ['1D', '2D', '3D', '5D'],
  1531. ]],
  1532. [15, [
  1533. ['500', '1000', '2000', '4000'],
  1534. ]],
  1535. [16, [
  1536. ['500', '1000', '2000', '4000'],
  1537. ]],
  1538. [22, [
  1539. ['<鍵開け-3>', '<鍵開け-5>', '<鍵開け-7>', '<鍵開け-11>'],
  1540. ]],
  1541. [23, [
  1542. ['<罠-3>', '<罠-5>', '<罠-7>', '<罠-11>'],
  1543. ]],
  1544. [24, [
  1545. ['<罠-3><鍵開け-3>', '<罠-5><鍵開け-5>', '<罠-7><鍵開け-7>', '<罠-11><鍵開け-11>'],
  1546. ]],
  1547. [25, [
  1548. ['<罠-5>', '<罠-5>', '<罠-7>', '<罠-11>'],
  1549. ['100', '200', '300', '500'],
  1550. ]],
  1551. [26, [
  1552. ['<罠-5>', '<罠-5>', '<罠-7>', '<罠-11>'],
  1553. ]],
  1554. [31, [
  1555. ['<登攀>', '<登攀-2>', '<登攀-4>', '<登攀-7>'],
  1556. ]],
  1557. [32, [
  1558. ['<運転/アカシックホイール>', '<運転/アカシックホイール-2>', '<運転/アカシックホイール/-4>', '<運転/アカシックホイール-7>'],
  1559. ]],
  1560. [33, [
  1561. ['<生存>', '<生存-2>', '<生存-4>', '<生存-7>'],
  1562. ]],
  1563. [35, [
  1564. ['<神秘学>', '<神秘学-2>', '<神秘学-4>', '<神秘学-7>'],
  1565. ]],
  1566. [36, [
  1567. ['「体力」', '「体力-2」', '「体力-4」', '「体力-8」'],
  1568. ]],
  1569. [41, [
  1570. ['キャンディークラウン(CL40)', 'キャンディークラウン(CL40)「1D-3」匹(最低1匹)', 'キャンディークラウン(CL40)「1D-2」匹(最低1匹)、出目が6だった場合ゴールデンクラウン(CL177)1匹', 'ゴールデンクラウン(CL177)'],
  1571. ]],
  1572. [42, [
  1573. ['ウイングスレイブ(CL4)×2とエンカウント', 'ウイングスレイブ(CL8)×2とエンカウント、致傷力+1、命中+2、HP+8', 'ウイングスレイブ(CL12)×2とエンカウント、致傷力+3、命中+6、HP+16', 'ガルーダ(CL40)×2とエンカウント'],
  1574. ]],
  1575. [43, [
  1576. ['ブラックナイト(CL10)、ソルジャー(CL4)×2、オーク(CL3)', 'ブラックナイト(CL10)×2、ハタモト(CL10)、サーバント(CL5)', 'サーバントマスター(CL35)、ヘルハウンド(CL12)×2', 'ジェネラル(CL55)、サーバントマスター(CL35)、ケルベロス(CL33)'],
  1577. ]],
  1578. [44, [
  1579. ['ガーゴイル(CL10)とエンカウント', 'ガーゴイル(CL15)とエンカウント、以下のように強化', 'ザッハーク(CL39)とエンカウント', '銀河龍ラクテア(CL90)とエンカウント'],
  1580. ['ガーゴイル', 'ガーゴイル', 'ザッハーク', '銀河龍ラクテア'],
  1581. ['', '
  1582. ----------
  1583. ガーゴイル(CL15) 魔族/岩石
  1584. ST20 DX13 IQ13 HT18 HP63 FP33
  1585. 受防3 防護18 移動6(飛行) よけ6 受け8 止め-
  1586. 宝石への命中判定ペナルティは-10
  1587. ガーゴイルの戦槌16(両手メイス)・・・命中20 3D+8「叩き」 重量5
  1588. ・ニンジャ
  1589. 行動:【ハイドインシャドウ】 FP1 姿を消す 「視覚-5」で発見可能
  1590. ・グラント
  1591. 行動:【グランドインペイル+3】+【エクステンドインペイル+1】(両手メイス) FP10
  1592. 3D+8「叩き」 受動防御無視「よけ」のみ 半径3ヘクス攻撃 射程5
  1593. 行動:【トルマリンスパーク+2】+【チェーンスパーク】(両手メイス) FP7
  1594. 3D+8「叩き」 命中もしくは「受け」「止め」時に電撃で2D+2の追加ダメージ
  1595. 行動:【グラビティブレイク+2】+【グラビティパニッシュ】(両手メイス) FP7
  1596. 3D+13「叩き」 「荷重レベル+3」の回避ペナルティ 命中後1ターンペナルティ持続
  1597. ----------', '', ''],
  1598. ]],
  1599. [45, [
  1600. ['カボチャの魔女(CL8)×2とエンカウント', 'カボチャの魔女(CL10)×2とエンカウント、《カボチャの雨》の致傷力+1Dされ、生命力-1で気絶判定、HP+2', 'カボチャの魔女(CL14)×2とエンカウント、《カボチャの雨》の致傷力+2Dされ生命力-3で気絶判定、HP+6', 'カボチャの大魔女(CL35)×2とエンカウント'],
  1601. ['', '', '', '
  1602. ----------
  1603. カボチャの大魔女(CL35) 魔族
  1604. ST11 DX15 IQ20 HT15 HP120 MP160 FP81
  1605. 受防1 防護4 移動10(飛行)よけ10 受け- 止め-
  1606. <戦術20> イニシアチブ値12
  1607. ・ソーサルギア
  1608. 《韋駄天》《火炎武器》《氷結武器》《電撃武器》《べたべた》
  1609. 《音噴射》《集団誘眠》《粉砕8》
  1610. ・センチュリオン
  1611. イニシ:【ファーストムーブ】(戦術) FP3 イニシアチブ判定に自動的に勝利
  1612. ・アークメイジ
  1613. ダメージ後:【マナシールド+2】 FP3 HPダメージをMPで肩代わり 1ターンに3回まで
  1614. 支援:【ダブルキャスト】 FP5 次の行動ターンに連続で魔法が使用可能
  1615. 行動:【テンペスト】 FP7 他の魔法に追加使用 「通常」の魔法や呪術を周囲半径10ヘクスに CT:シナリオ
  1616. ・オリジナル魔法
  1617. 《カボチャの大災厄》(パンプキンカタストロフ) 通常 消費30
  1618. 半径5ヘクスの敵味方を区別せず6Dの「叩き」ダメージを与える。
  1619. 隙間なく降り注ぐカボチャは回避不可能で、
  1620. 1点でもダメージを受けると「生命力-6」判定を行い、失敗すると気絶する
  1621. ----------'],
  1622. ]],
  1623. [46, [
  1624. ['フェニックス(CL25)', 'フェニックス(CL30)', 'フェニックス(CL35)', '煉獄フェニックス(CL85)'],
  1625. ['', '、クチバシの致傷力+2、命中+4、アクセルギア【ディザスタープログラム】を追加', '、クチバシの致傷力+4、命中+8、アクセルギア【ディザスタープログラム】を追加', ''],
  1626. ]],
  1627. [51, [
  1628. ['「敏捷力-3」', '「敏捷力-4」', '「敏捷力-5」', '「敏捷力-7」'],
  1629. ['3D+5', '5D+5', '7D+5', '11D+5'],
  1630. ]],
  1631. [52, [
  1632. ['<登攀>', '<登攀-2>', '<登攀-4>', '<登攀-7>'],
  1633. ['4D', '6D', '8D', '12D'],
  1634. ]],
  1635. [53, [
  1636. ['「敏捷力」', '「敏捷力-2」', '「敏捷力-4」', '「敏捷力-7」'],
  1637. ['', '', '', '判定失敗時さらに最も単価の高い消耗品を自分のヘクスに落とす(拾うには行動消費)'],
  1638. ]],
  1639. [54, [
  1640. ['', '', '《べたべた》判定後、『銀糸の甲殻』アルゲントゥム(CL40・ネームド)とエンカウント。', '《べたべた》判定後、『銀糸の甲殻』アルゲントゥム(CL50・ネームド)×2とエンカウント、あらゆる致傷力+2D、命中判定+8。'],
  1641. ]],
  1642. [55, [
  1643. ['<生存-3>', '<生存-5>', '<生存-7>', '<生存-11>'],
  1644. ['4D', '5D', '6D', '8D'],
  1645. ]],
  1646. [56, [
  1647. ['防護点2、HP80', '防護点4、HP120', '防護点6、HP160', '防護点8、HP320'],
  1648. ]],
  1649. [61, [
  1650. ['-2', '-3', '-4', '-6'],
  1651. ]],
  1652. [62, [
  1653. ['100', '200', '300', '500'],
  1654. ]],
  1655. [63, [
  1656. ['', '', '1Dを2回振って属性決定、2回攻撃で破壊。', '1Dを3回振って属性決定、3回攻撃で破壊。'],
  1657. ]],
  1658. [64, [
  1659. ['「ジャンボ串焼き」', '「ジャンボ串焼き」「グラント風香草焼き」のいずれか(選択可能)', '「ジャンボ串焼き」「グラント風香草焼き」「ドラゴンステーキ」のいずれか(選択可能)', '「ジャンボ串焼き」「グラント風香草焼き」「ドラゴンステーキ」「マツザカスペシャル」のいずれか(選択可能)'],
  1660. ]],
  1661. [65, [
  1662. ['<植物学><医師><動植物知識-3>', '<植物学-2><医師-2><動植物知識-5>', '<植物学-4><医師-4><動植物知識-7>', '<植物知識-7><医師-7><動植物知識-11>'],
  1663. ['100', '200', '300', '500'],
  1664. ]],
  1665. [66, [
  1666. ['「視覚-5」か<武具屋>', '「視覚-7」か<武具屋-2>', '「視覚-9」か<武具屋-4>', '「視覚-13」か<武具屋-7>'],
  1667. ['10000', '20000', '30000', '60000'],
  1668. ]],
  1669. ]
  1670. when: 0 when 4 # 水辺
  1671. table = [
  1672. [12, [
  1673. ['1D', '2D', '3D', '5D'],
  1674. ]],
  1675. [16, [
  1676. ['<毒物-5>', '<毒物-7>', '<毒物-9>', '<毒物-13>'],
  1677. ['1D', '2D', '3D', '5D']
  1678. ]],
  1679. [22, [
  1680. ['<鍵開け-3>', '<鍵開け-5>', '<鍵開け-7>', '<鍵開け-11>']
  1681. ]],
  1682. [23, [
  1683. ['<罠-3>', '<罠-5>', '<罠-7>', '<罠-11>']
  1684. ]],
  1685. [24, [
  1686. ['<罠-3><鍵開け-3>', '<罠-5><鍵開け-5>', '<罠-7><鍵開け-7>', '<罠-11><鍵開け-11>']
  1687. ]],
  1688. [25, [
  1689. ['<罠-5>', '<罠-5>', '<罠-7>', '<罠-11>'],
  1690. ['100', '200', '300', '500'],
  1691. ]],
  1692. [26, [
  1693. ['<罠-5>', '<罠-5>', '<罠-7>', '<罠-11>']
  1694. ]],
  1695. [31, [
  1696. ['<生存>', '<生存-2>', '<生存-4>', '<生存-7>'],
  1697. ]],
  1698. [32, [
  1699. ['<登攀>か<軽業>', '<登攀-2>か<軽業-2>', '<登攀-4>か<軽業-4>', '<登攀-8>か<軽業-8>'],
  1700. ]],
  1701. [34, [
  1702. ['「視覚-5」', '「視覚-6」', '「視覚-7」', '「視覚-11」'],
  1703. ]],
  1704. [35, [
  1705. ['「体力-5」', '「体力-6」', '「体力-7」', '「体力-9」'],
  1706. ]],
  1707. [36, [
  1708. ['<船乗り-3>', '<船乗り-5>', '<船乗り-7>', '<船乗り-11>'],
  1709. ]],
  1710. [41, [
  1711. ['キャンディークラウン(CL40)', 'キャンディークラウン(CL40)「1D-3」匹(最低1匹)', 'キャンディークラウン(CL40)「1D-2」匹(最低1匹)、出目が6だった場合ゴールデンクラウン(CL177)1匹', 'ゴールデンクラウン(CL177)']
  1712. ]],
  1713. [42, [
  1714. ['アシガル(CL4)×2、アイスリザード(CL7)', 'ハタモト(CL10)×2、アイスリザード(CL7)', 'ナイトライダー(CL15)×2、アイスメイデン(CL10)', 'スカーレス(CL38)×3'],
  1715. ]],
  1716. [43, [
  1717. ['アンブッシュマン(CL5)×3とエンカウント', 'アンブッシュマン(CL9)×3とエンカウント、致傷力+2、命中+4、HP+8、FP+4', 'アンブッシュマン(CL13)×3とエンカウント、致傷力+4、命中+8、HP16、FP+8', 'シャドウストーカー(CL35)×2とエンカウント'],
  1718. ['「視覚-5」', '「視覚-5」', '「視覚-5」', '「視覚-9」'],
  1719. ]],
  1720. [44, [
  1721. ['アップルドール(CL12)', 'アップルドール(CL12)×2', 'アップルドール(CL12)×2とポイズンリリー(CL7)×2', '水陸両用改造型アップルドール(CL30)×2とバリアリーフ(CL27)'],
  1722. ]],
  1723. [45, [
  1724. ['ジェルスケルトン(CL10)とエンカウント', 'ジェルスケルトン(CL15)とエンカウント、ST21、命中+2、防護6、HP+15、FP+10', 'ジェルスケルトン(CL20)とエンカウント、ST25、命中+4、防護8、HP+30、FP+20', 'ジェルスケルトン(CL40)とエンカウント、ST45、命中+12、防護12、HP+90、FP+60'],
  1725. ]],
  1726. [46, [
  1727. ['ナイトライダー(CL15)とエンカウント', 'ナイトライダー(CL15)×2とエンカウント', 'ナイトライダー(CL15)×2、バリアリーフ(CL27)とエンカウント', 'ジェネラル(CL55)、バリアリーフ(CL27)とエンカウント、ジェネラルはペット「スワンプランナー」に<乗馬20>で騎乗、移動8'],
  1728. ]],
  1729. [51, [
  1730. ['「意志-3」', '「意志-4」', '「意志-5」', '「意志-7」'],
  1731. ]],
  1732. [52, [
  1733. ['<水泳>', '<水泳-2>', '<水泳-4>', '<水泳-8>'],
  1734. ['8D', '10D', '12D', '20D'],
  1735. ]],
  1736. [53, [
  1737. ['「よけ」', '「よけ-2」', '「よけ-4」', '「よけ-8」'],
  1738. ['4D', '6D', '8D', '12D'],
  1739. ]],
  1740. [54, [
  1741. ['<武具屋>', '<武具屋-2>', '<武具屋-4>', '<武具屋-8>'],
  1742. ['-2', '-3', '-4', '-6'],
  1743. ]],
  1744. [55, [
  1745. ['「生命力」', '「生命力-2」', '「生命力-4」', '「生命力-8」'],
  1746. ['1D', '2D', '3D', '5D'],
  1747. ]],
  1748. [56, [
  1749. ['<地質学>か「聴覚-7」', '<地質学-2>か「聴覚-9」', '<地質学-4>か「聴覚-11」', '<地質学-8>か「聴覚-15」'],
  1750. ['5D', '7D', '9D', '13D'],
  1751. ]],
  1752. [61, [
  1753. ['スワンプランナー', 'スワンプランナー', 'スワンプランナー', 'ゴールデンコーン'],
  1754. ['<応急処置-4>か<獣医>', '<応急処置-4>か<獣医>', '<応急処置-4>か<獣医>', '<応急処置-10>か<獣医-6>'],
  1755. ]],
  1756. [62, [
  1757. ['<釣り-5>', '<釣り-7>', '<釣り-9>', '<釣り-13>'],
  1758. ['3000', '6000', '9000', '18000'],
  1759. ]],
  1760. [63, [
  1761. ['<歌唱-3>か<作詞>', '<歌唱-5>か<作詞-2>', '<歌唱-7>か<作詞-4>', '<歌唱-11>か<作詞-8>'],
  1762. ['2D', '3D', '4D', '6D'],
  1763. ]],
  1764. [64, [
  1765. ['<釣り20>', '<釣り22>', '<釣り24>', '<釣り28>'],
  1766. ]],
  1767. [65, [
  1768. ['<探索-3>', '<探索-5>', '<探索-7>', '<探索-11>'],
  1769. ['100', '200', '300', '500'],
  1770. ]],
  1771. [66, [
  1772. ['<動植物知識>', '<動植物知識-2>', '<動植物知識-4>', '<動植物知識-8>'],
  1773. ['1000', '2000', '3000', '5000'],
  1774. ]],
  1775. ]
  1776. when: 0 when 5 # 森林
  1777. table = [
  1778. [13, [
  1779. ['2D', '3D', '4D', '6D'],
  1780. ]],
  1781. [16, [
  1782. ['<植物学-3>か<動植物知識-5>', '<植物学-5>か<動植物知識-7>', '<植物学-7>か<動植物知識-9>', '<植物学-11>か<動植物知識-13>'],
  1783. ['3D', '4D', '6D', '9D'],
  1784. ]],
  1785. [22, [
  1786. ['<鍵開け-3>', '<鍵開け-5>', '<鍵開け-7>', '<鍵開け-11>']
  1787. ]],
  1788. [23, [
  1789. ['<罠-3>', '<罠-5>', '<罠-7>', '<罠-11>']
  1790. ]],
  1791. [24, [
  1792. ['<罠-3><鍵開け-3>', '<罠-5><鍵開け-5>', '<罠-7><鍵開け-7>', '<罠-11><鍵開け-11>']
  1793. ]],
  1794. [25, [
  1795. ['<罠-5>', '<罠-5>', '<罠-7>', '<罠-11>'],
  1796. ['100', '200', '300', '500'],
  1797. ]],
  1798. [26, [
  1799. ['<罠-5>', '<罠-5>', '<罠-7>', '<罠-11>']
  1800. ]],
  1801. [31, [
  1802. ['<生存>', '<生存-2>', '<生存-4>', '<生存-8>'],
  1803. ]],
  1804. [32, [
  1805. ['<考古学>', '<考古学-2>', '<考古学-4>', '<考古学-8>'],
  1806. ]],
  1807. [34, [
  1808. ['「生命力」', '「生命力-2」', '「生命力-4」', '「生命力-8」'],
  1809. ['1D', '2D', '3D', '5D'],
  1810. ]],
  1811. [36, [
  1812. ['2D', '3D', '4D', '6D'],
  1813. ]],
  1814. [41, [
  1815. ['キャンディークラウン(CL40)', 'キャンディークラウン(CL40)「1D-3」匹(最低1匹)', 'キャンディークラウン(CL40)「1D-2」匹(最低1匹)、出目が6だった場合ゴールデンクラウン(CL177)1匹', 'ゴールデンクラウン(CL177)']
  1816. ]],
  1817. [42, [
  1818. ['スターゲイザー(CL10)、オーク(CL3)×3', 'スターゲイザー(CL10)、ヘルハウンド(CL12)×2', 'コスモロジスト(CL20)、ナイトライダー(CL15)×2', 'サーバントマスター(CL35)、ガルーダ(40)×2'],
  1819. ['オーク', 'ヘルハウンド', 'ナイトライダー', 'ガルーダ'],
  1820. ['スターゲイザーのMPを15点', 'スターゲイザーのMPを10点', 'コスモロジストのMPを10点', 'サーバントマスターのMPを10点'],
  1821. ]],
  1822. [43, [
  1823. ['オウルセイージ(CL5)×2、インプ(CL3)、オーク(CL3)', 'オウルセージ(CL5)×3、キメラ(CL15)', 'オウルコマンダー(CL18)×2、ブラックナイト(CL10)×2', 'オウルコマンダー(CL18)×2、ヨウコ(CL30)、アダマンゴーレム(CL45)'],
  1824. ['2', '3', '4', '6'],
  1825. ]],
  1826. [44, [
  1827. ['gールデンビースト(CL10)とエンカウント', 'ゴールデンビースト(CL15)とエンカウント、致傷力+2、命中+4、HP+10、FP+10', 'ゴールデンビースト(CL25)とエンカウント、致傷力+4、命中+10、HP+30、FP+30', 'イビルオーメン(CL42)×2とエンカウント'],
  1828. ]],
  1829. [45, [
  1830. ['アップルドール(CL12)、ポイズンリリー(CL7)', 'アップルドール(CL12)×2、ポイズンリリー(CL7)', '水陸両用改造型アップルドール(CL30)、グリーンアクトレス(CL22)', '水陸両用改造型アップルドール(CL30)×2、リッチ(CL44)'],
  1831. ['<忍び>', '<忍び-1>', '<忍び-2>', '<忍び-4>'],
  1832. ]],
  1833. [46, [
  1834. ['キメラ(CL15)とエンカウント', 'キメラ(CL20)とエンカウント、防護+2、致傷力+2、命中+4、HP+20、FP+10', '防護+4、致傷力+6、命中+10、HP+60、FP+30', 'キメラグレート(CL60)とエンカウント'],
  1835. ]],
  1836. [51, [
  1837. ['<毒物><植物学><動植物知識-3>', '<毒物-2><植物学-2><動植物知識-5>', '<毒物-4><植物学-4><動植物知識-7>', '<毒物-8><植物学-8><動植物知識-11>'],
  1838. ]],
  1839. [52, [
  1840. ['2D', '3D', '4D', '5D'],
  1841. ]],
  1842. [53, [
  1843. ['2D', '4D', '6D', '10D'],
  1844. ['「体力-5」', '「体力-7」', '「体力-9」', '「体力-13」'],
  1845. ['<罠-5>', '<罠-7>', '<罠-9>', '<罠-13>'],
  1846. ]],
  1847. [54, [
  1848. ['1D', '2D', '3D', '5D'],
  1849. ['「生命力」', '「生命力-2」', '「生命力-4」', '「生命力-8」'],
  1850. ]],
  1851. [55, [
  1852. ['<植物学>か<動植物知識-3>', '<植物学-2>か<動植物知識-5>', '<植物学-2>か<動植物知識-5>', '<植物学-2>か<動植物知識-5>'],
  1853. ['3D', '5D', '7D', '11D'],
  1854. ]],
  1855. [56, [
  1856. ['「生命力」', '「生命力-2」', '「生命力-4」', '「生命力-8」'],
  1857. ['1', '2', '3', '4'],
  1858. ]],
  1859. [62, [
  1860. ['<踊り>', '<踊り-2>', '<踊り-4>', '<踊り-8>'],
  1861. ['200', '400', '600', '1000'],
  1862. ]],
  1863. [63, [
  1864. ['<偽装-5>', '<偽装-9>', '<偽装-13>', '<偽装-19>'],
  1865. ['狩人の羽帽子', '緊急召喚の宝珠', '毒の香水瓶', '女王の花冠'],
  1866. ]],
  1867. [64, [
  1868. [
  1869. '1:高級クイックHPポーション
  1870. 2:高級クイックMPポーション
  1871. 3:高級クイックスタミナポーション
  1872. 4:クイック解毒ポーション
  1873. 5:クイック中和ポーション
  1874. 6:高級抵抗ポーション',
  1875. '1:高級クイックHPポーション
  1876. 2:高級クイックMPポーション
  1877. 3:高級クイックスタミナポーション
  1878. 4:クイック解毒ポーション
  1879. 5:クイック中和ポーション
  1880. 6:高級抵抗ポーション',
  1881. '1:高級クイックHPポーション
  1882. 2:最高級クイックMPポーション
  1883. 3:最高級クイックスタミナポーション
  1884. 4:加速ポーション
  1885. 5:加速ポーション
  1886. 6:最高級抵抗ポーション',
  1887. '1:特製クイックHPポーション
  1888. 2:特製クイックHPポーション
  1889. 3:特製クイックMPポーション
  1890. 4:特製クイックMPポーション
  1891. 5:特製クイックスタミナポーション
  1892. 6:特製クイックスタミナポーション'
  1893. ],
  1894. ]],
  1895. ]
  1896. when: 0 when 6 # 墓地
  1897. table = [
  1898. [12, [
  1899. ['2D', '3D', '4D', '6D'],
  1900. ['1D', '3D', '5D', '8D'],
  1901. ]],
  1902. [13, [
  1903. ['2D', '3D', '4D', '6D'],
  1904. ]],
  1905. [15, [
  1906. ['1000', '2000', '3000', '5000'],
  1907. ]],
  1908. [22, [
  1909. ['<鍵開け-3>', '<鍵開け-5>', '<鍵開け-7>', '<鍵開け-11>']
  1910. ]],
  1911. [23, [
  1912. ['<罠-3>', '<罠-5>', '<罠-7>', '<罠-11>']
  1913. ]],
  1914. [24, [
  1915. ['<罠-3><鍵開け-3>', '<罠-5><鍵開け-5>', '<罠-7><鍵開け-7>', '<罠-11><鍵開け-11>']
  1916. ]],
  1917. [25, [
  1918. ['<罠-5>', '<罠-5>', '<罠-7>', '<罠-11>'],
  1919. ['100', '200', '300', '500'],
  1920. ]],
  1921. [26, [
  1922. ['<罠-5>', '<罠-5>', '<罠-7>', '<罠-11>']
  1923. ]],
  1924. [31, [
  1925. ['「視覚-5」', '「視覚-7」', '「視覚-9」', '「視覚-13」'],
  1926. ]],
  1927. [33, [
  1928. ['<生存>', '<生存-2>', '<生存-4>', '<生存-8>'],
  1929. ['2', '4', '6', '10'],
  1930. ]],
  1931. [36, [
  1932. ['-1', '-2', '-3', '-4'],
  1933. ]],
  1934. [41, [
  1935. ['キャンディークラウン(CL40)', 'キャンディークラウン(CL40)「1D-3」匹(最低1匹)', 'キャンディークラウン(CL40)「1D-2」匹(最低1匹)、出目が6だった場合ゴールデンクラウン(CL177)1匹', 'ゴールデンクラウン(CL177)']
  1936. ]],
  1937. [42, [
  1938. ['スケルトン(CL3)×3とエンカウント', 'スケルトン(CL3)×6とエンカウント、致傷力+2、命中+2', 'デッドリーローズ(CL15)×3とエンカウント、スケルトン化しており「叩きダメージボーナス2倍」を追加', '堕ちた黒竜(CL48)×3とエンカウント、スケルトン化しており「叩きダメージボーナス2倍」を追加'],
  1939. ]],
  1940. [43, [
  1941. ['ポイズンリリー(CL7)、ファントム(CL5)×2', 'ポイズンリリー(CL7)、ゴースト(CL10)×2', 'グリーンアクトレス(CL22)、デュラハン(CL22)×2', 'グリーンアクトレス(CL22)、ヒトキリ(CL33)×2'],
  1942. ['ポイズンリリー', 'ポイズンリリー', 'グリーンアクトレス', 'グリーンアクトレス'],
  1943. ['1', '2', '3', '4'],
  1944. ]],
  1945. [44, [
  1946. ['「保険」に入っていなければPC達は死亡し、グレイヴディガーの配下にさせられてしまう。冒険はここで終了だ。', '「保険」に入っていなければPC達は死亡し、グレイヴディガーの配下にさせられてしまう。冒険はここで終了だ。', '「保険」に入っていなければPC達は死亡し、グレイヴディガーの配下にさせられてしまう。冒険はここで終了だ。', '『葬送者』グレイヴディガー(CL200・魔将)、『ディガー様親衛隊隊長』フュネライユ(CL66・ネームド)、エルダーリッチ(CL55)、イビルオーメン(CL42)×2とエンカウント。'],
  1947. ]],
  1948. [45, [
  1949. ['ゴースト(CL10)、ソルジャー(CL4)×2', 'ゴースト(CL10)、ハタモト(CL10)×2', 'デュラハン(CL22)、ハタモト(CL10)×3', 'エルダーリッチ(CL55)、アダマンゴーレム(CL45)×2'],
  1950. ['ゴースト', 'ゴースト', 'デュラハン', 'エルダーリッチ'],
  1951. ['100', '200', '300', '500'],
  1952. ]],
  1953. [46, [
  1954. ['ボーンスネーク(CL20)とエンカウント', 'ボーンスネーク(CL20)×2とエンカウント', 'ボーンスネーク(CL20)×3とエンカウント、致傷力+2', 'ラダマンティスの蛇(CL50)×2とエンカウント、半ば化石になりかけており「叩きダメージボーナス2倍」を追加'],
  1955. ]],
  1956. [51, [
  1957. ['「意志」', '「意志-2」', '「意志-4」', '「意志-8」'],
  1958. ]],
  1959. [52, [
  1960. ['「よけ」', '「よけ-2」', '「よけ-4」', '「よけ-8」'],
  1961. ['3D', '5D', '7D', '11D'],
  1962. ]],
  1963. [53, [
  1964. ['<建築>', '<建築-2>', '<建築-4>', '<建築-8>'],
  1965. ['3D', '5D', '7D', '11D'],
  1966. ]],
  1967. [54, [
  1968. ['「体力-3」', '「体力-5」', '「体力-7」', '「体力-11」'],
  1969. ['ジェルスケルトン(CL10)', 'ボーンスネーク(CL20)', 'リッチ(CL44)', '『ディガー様親衛隊隊長』フュネライユ(CL66・ネームド)'],
  1970. ]],
  1971. [55, [
  1972. ['100', '200', '400', '1000'],
  1973. ['3D', '5D', '7D', '11D'],
  1974. ]],
  1975. [61, [
  1976. ['5D', '7D', '9D', '13D'],
  1977. ]],
  1978. [62, [
  1979. ['「生命力」', '「生命力-1」', '「生命力-2」', '「製絵魅力-4」'],
  1980. ]],
  1981. [63, [
  1982. ['-1', '-2', '-3', '-4'],
  1983. ['2000', '6000', '20000', '60000'],
  1984. ]],
  1985. [64, [
  1986. [
  1987. '1:火炎弾×5(アームガン弾薬)
  1988. 2:冷凍弾×5(アームガン弾薬)
  1989. 3:貫甲弾×3(アームガン弾薬)
  1990. 4:簡易ソーサルセット(装飾品)
  1991. 5:ギアテール(装飾品)
  1992. 6:パイルバンカー高速収納装置(装飾品)',
  1993. '1:火炎弾×5(アームガン弾薬)
  1994. 2:冷凍弾×5(アームガン弾薬)
  1995. 3:貫甲弾×3(アームガン弾薬)
  1996. 4:ゴーレムアーム(装飾品)
  1997. 5:ゴーレムアーム(装飾品)
  1998. 6:ホイールブースター(装飾品)',
  1999. '1:火炎弾×5(アームガン弾薬)
  2000. 2:冷凍弾×5(アームガン弾薬)
  2001. 3:貫甲弾×3(アームガン弾薬)
  2002. 4:ヒュージーミスリルフィスト(装飾品)
  2003. 5:ヒュージーミスリルフィスト(装飾品)
  2004. 6:ヒュージーブレード(両手剣)',
  2005. '1:火炎弾×5(アームガン弾薬)
  2006. 2:冷凍弾×5(アームガン弾薬)
  2007. 3:貫甲弾×3(アームガン弾薬)
  2008. 4:ヒュージーブレード(両手剣)
  2009. 5:ヒュージーブレード(両手剣)
  2010. 6:ナグルファル装甲(装飾品)'
  2011. ],
  2012. ]],
  2013. [65, [
  2014. ['200', '500', '1000', '5000'],
  2015. ['カロン(CL12)×2とエンカウント', 'カロン(CL12)×2とエンカウント、致傷力+2', 'カロンキャプテン(CL25)×2とエンカウント', 'エルダーリッチ(CL55)×2とエンカウント'],
  2016. ]],
  2017. [66, [
  2018. ['墓場のブラックナイト(CL10)とエンカウント', '墓場のブラックナイト(CL20)とエンカウント', '墓場のブラックナイト(CL30)とエンカウント', '墓場のハイペリオンダミー(CL100)とエンカウント'],
  2019. ['キメラウェポンズ', 'キメラウェポンズ', 'キメラウェポンズ', 'グレートキメラウェポンズ'],
  2020. [
  2021. '墓場のブラックナイト(標準CL10) 魔族
  2022. 攻防ともに高い能力を持つ、魔族のエリート騎士。
  2023. 常時《倍速》で武器には《戻る武器》がかかっている。
  2024. ST16 DX15 IQ12 HT15 HP45 FP26
  2025. 受防3(金属鎧) 防護6(金属鎧) 移動5 よけ5 受け9 止め-
  2026. 常時《倍速》 <跳躍18>
  2027. キメラウェポンズ18(特殊)・・・攻撃ごとに形状変化 上質 壊れない 《戻る武器》
  2028. キメラウェポンズ/両手剣・・・命中21 2D+6「切り」 射程2
  2029. キメラウェポンズ/両手メイス・・・命中21 2D+7「叩き」 射程2
  2030. キメラウェポンズ/両手斧・・・命中21 2D+6「切り」 射程2
  2031. キメラウェポンズ/長槍・・・命中21 2D+6「刺し」 射程3
  2032. ・ウォリアー
  2033. 行動:【クロスブレイク】+【ハイスピードブレイク】(両手剣) FP6 2D+7「切り」 2回攻撃
  2034. 行動:【リープアタック】+【ジェノサイドリープ】(両手剣) FP4
  2035. 2D+6「切り」<跳躍>でフェイント 2体まで攻撃 移動妨害・大振りにならない
  2036. 行動:【ヘビースマッシュ】(両手メイス) FP2 2D+13「叩き」
  2037. 行動:【トマホークミサイル】(両手斧) FP2 2D+8「切り」 回避-2 半致傷16 最大射程24
  2038. 行動:【スターダストフォール】(長槍) FP3 1D+6 回避-3 半致傷16 最大射程24
  2039. 行動:【ワールウィンド】(長槍) FP3 2D+6「切り」 周囲半径3ヘクス
  2040. ・オリジナル
  2041. 【騎士の闘気】
  2042. 使用:常時 判定:なし 疲労:なし 強化:×
  2043. ターンの最初にFPを3点回復する。
  2044. 所有レア:漆黒の甲冑(鎧)',
  2045. '墓場のブラックナイト(標準CL20) 魔族
  2046. 攻防ともに高い能力を持つ、魔族のエリート騎士。
  2047. 常時《倍速》で武器には《戻る武器》がかかっている。
  2048. ST16 DX15 IQ12 HT15 HP75 FP36
  2049. 受防3(金属鎧) 防護6(金属鎧) 移動5 よけ5 受け9 止め-
  2050. 常時《倍速》 <跳躍18>
  2051. キメラウェポンズ18(特殊)・・・攻撃ごとに形状変化 上質 壊れない 《戻る武器》
  2052. キメラウェポンズ/両手剣・・・命中31 2D+10「切り」 射程2
  2053. キメラウェポンズ/両手メイス・・・命中31 2D+11「叩き」 射程2
  2054. キメラウェポンズ/両手斧・・・命中31 2D+10「切り」 射程2
  2055. キメラウェポンズ/長槍・・・命中31 2D+10「刺し」 射程3
  2056. ・ウォリアー
  2057. 行動:【クロスブレイク】+【ハイスピードブレイク】(両手剣) FP6 2D+11「切り」 2回攻撃
  2058. 行動:【リープアタック】+【ジェノサイドリープ】(両手剣) FP4
  2059. 2D+10「切り」<跳躍>でフェイント 2体まで攻撃 移動妨害・大振りにならない
  2060. 行動:【ヘビースマッシュ】(両手メイス) FP2 2D+17「叩き」
  2061. 行動:【トマホークミサイル】(両手斧) FP2 2D+12「切り」 回避-2 半致傷16 最大射程24
  2062. 行動:【スターダストフォール】(長槍) FP3 1D+10 回避-3 半致傷16 最大射程24
  2063. 行動:【ワールウィンド】(長槍) FP3 2D+10「切り」 周囲半径3ヘクス
  2064. ・オリジナル
  2065. 【騎士の闘気】
  2066. 使用:常時 判定:なし 疲労:なし 強化:×
  2067. ターンの最初にFPを3点回復する。
  2068. 所有レア:漆黒の甲冑(鎧)',
  2069. '墓場のブラックナイト(標準CL30) 魔族
  2070. 攻防ともに高い能力を持つ、魔族のエリート騎士。
  2071. 常時《倍速》で武器には《戻る武器》がかかっている。
  2072. ST16 DX15 IQ12 HT15 HP105 FP46
  2073. 受防3(金属鎧) 防護6(金属鎧) 移動5 よけ5 受け9 止め-
  2074. 常時《倍速》 <跳躍18>
  2075. キメラウェポンズ18(特殊)・・・攻撃ごとに形状変化 上質 壊れない 《戻る武器》
  2076. キメラウェポンズ/両手剣・・・命中41 2D+14「切り」 射程2
  2077. キメラウェポンズ/両手メイス・・・命中41 2D+15「叩き」 射程2
  2078. キメラウェポンズ/両手斧・・・命中41 2D+14「切り」 射程2
  2079. キメラウェポンズ/長槍・・・命中41 2D+14「刺し」 射程3
  2080. ・ウォリアー
  2081. 行動:【クロスブレイク】+【ハイスピードブレイク】(両手剣) FP6 2D+15「切り」 2回攻撃
  2082. 行動:【リープアタック】+【ジェノサイドリープ】(両手剣) FP4
  2083. 2D+14「切り」<跳躍>でフェイント 2体まで攻撃 移動妨害・大振りにならない
  2084. 行動:【ヘビースマッシュ】(両手メイス) FP2 2D+21「叩き」
  2085. 行動:【トマホークミサイル】(両手斧) FP2 2D+16「切り」 回避-2 半致傷16 最大射程24
  2086. 行動:【スターダストフォール】(長槍) FP3 1D+14 回避-3 半致傷16 最大射程24
  2087. 行動:【ワールウィンド】(長槍) FP3 2D+14「切り」 周囲半径3ヘクス
  2088. ・オリジナル
  2089. 【騎士の闘気】
  2090. 使用:常時 判定:なし 疲労:なし 強化:×
  2091. ターンの最初にFPを3点回復する。
  2092. 所有レア:漆黒の甲冑(鎧)',
  2093. '墓場のハイペリオンダミー(標準CL100) 魔族
  2094. 第三魔将ハイペリオンを模して造られたダミー装甲。
  2095. 常時《倍速》で武器には《戻る武器》がかかっている。
  2096. ST75 DX22 IQ15 HT27 HP527 FP275
  2097. 受防4 防護15 移動10 よけ10 受け14 止め-
  2098. バッドステータス無効 ファンブル無効 切り刺しダメージボーナス無効
  2099. 常時《倍速》 <戦術20> イニシアチブ値12 装備重量150kg
  2100. グレートキメラウェポンズ28(特殊)・・・攻撃ごとに形状変化 最高品質 《戻る武器》
  2101. キメラウェポンズ/両手剣・・・命中58 17D+10「切り」 射程2
  2102. キメラウェポンズ/両手メイス・・・命中58 17D+11「叩き」 射程2
  2103. キメラウェポンズ/両手斧・・・命中58 17D+10「切り」 射程2
  2104. キメラウェポンズ/長槍・・・命中58 17D+10「刺し」 射程3
  2105. 世界樹装甲・・・防護点が減少しない(一時的な「防護点無視」の効果は受ける)
  2106. 着用者のHPをターンの最初に10点回復する
  2107. ・ウォリアー
  2108. 行動:【クロスブレイク+5】+【ハイスピードブレイク+5】(両手剣) FP16
  2109. 17D+16「切り」 回避-5 2回攻撃
  2110. 行動:【ヘビースマッシュ+5】+【ヘビーストライク】(両手メイス) FP11
  2111. 17D+40「切り」 「受け」「止め」時に装備を破壊 「生命力-6」に失敗すると朦朧
  2112. 行動:【トマホークミサイル+5】+【トールハンマー】(両手斧) FP10
  2113. 命中64 17D+27「切り」 回避-2 半致傷750 最大射程1120
  2114. 行動:【スターダストフォール+5】+【プロミストビクトリー】(長槍) FP12
  2115. 8D+20「刺し」 必中クリティカル クリティカル表参照なし 射撃攻撃 半致傷75 最大射程112
  2116. 行動:【ワールウィンド+5】+【バイオレントウィンド】(長槍) FP
  2117. 17D+10+(移動距離÷2)「切り」 周囲半径3ヘクス 「敏捷-9」で転倒判定 大振りにならない
  2118. ・センチュリオン
  2119. イニシ:【ファーストムーブ】(戦術) FP3 イニシアチブ判定に自動的に勝利
  2120. 回避:【ツーハンドプロテクト】 FP3 武器技能の3分の2で「受け」を行う
  2121. 行動:【ソニックブーム+4】 FP7 他の技に追加使用 近接物理攻撃の射程が50に
  2122. ダメージ後:【アドバンストガード】 FP5 近接物理攻撃で受けた最終ダメージを半減 CT:次
  2123. ・マスターナイト
  2124. 行動:【グレートチャージ】 FP5 他の近接技に追加使用 致傷力+15
  2125. 行動:【シーズエンジン】 FP6 他の射撃技に追加使用 「切り」+3D 「刺し」+2D
  2126. ・オリジナル
  2127. 【無限の闘気】
  2128. 使用:常時 判定:なし 疲労:なし 強化:×
  2129. ターンの最初にFPを30点回復する。
  2130. 【障壁破壊】
  2131. 使用:常時 判定:なし 疲労:なし 強化:×
  2132. 移動および攻撃時に《物質障壁》《完全障壁》の影響を受けない。
  2133. また、ハイペリオンダミーの攻撃は受動防御のみで回避することができない。
  2134. 所有レア:世界樹装甲(鎧)'
  2135. ],
  2136. ]],
  2137. ]
  2138. else: 0 else
  2139. return "[ERROR:getRandomDiff]"
  2140. end
  2141. 16 result = get_table_by_number(dice23, table)
  2142. 16 return result[index][dif]
  2143. end
  2144. end
  2145. end
  2146. end

lib/bcdice/game_system/HarnMaster.rb

96.39% lines covered

88.0% branches covered

83 relevant lines. 80 lines covered and 3 lines missed.
25 total branches, 22 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class HarnMaster < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'HarnMaster'
  7. # ゲームシステム名
  8. 1 NAME = 'ハーンマスター'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'はあんますたあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定
  14.  1D100<=XX の判定時に致命的失敗・決定的成功を判定
  15. ・ショック判定(SHKx)
  16.  例)SHK13,3
  17. ・人型用 中段命中部位表 (SLH)/上段命中部位 (SLHU)/上段命中部位 (SLHD)
  18. MESSAGETEXT
  19. 1 register_prefix('SHK', 'SLH', 'SLHU', 'SLHD')
  20. 1 def result_1d100(total, _dice_total, cmp_op, target)
  21. 5 then: 1 else: 4 return Result.nothing if target == '?'
  22. 4 else: 4 then: 0 return nil unless cmp_op == :<=
  23. 4 then: 2 if total <= target
  24. 2 then: 1 if total % 5 == 0
  25. 1 Result.critical("決定的成功")
  26. else: 1 else
  27. 1 Result.success("成功")
  28. end
  29. else: 2 else
  30. 2 then: 1 if total % 5 == 0
  31. 1 Result.fumble("致命的失敗")
  32. else: 1 else
  33. 1 Result.failure("失敗")
  34. end
  35. end
  36. end
  37. 1 def eval_game_system_specific_command(command)
  38. 13 result = nil
  39. 13 case command
  40. when: 3 when /^SHK(\d*),(\d+)/i
  41. 3 toughness = Regexp.last_match(1).to_i
  42. 3 damage = Regexp.last_match(2).to_i
  43. 3 result = getCheckShockResult(damage, toughness)
  44. when: 10 when /SLH(U|D)?/i
  45. 10 type = Regexp.last_match(1)
  46. 10 result = getStrikeLocationHuman(type)
  47. else: 0 else
  48. result = nil
  49. end
  50. 13 return result
  51. rescue StandardError => e
  52. return e.message
  53. end
  54. 1 def getCheckShockResult(damage, toughness)
  55. 3 dice_list = @randomizer.roll_barabara(damage, 6)
  56. 3 dice = dice_list.sum()
  57. 3 diceText = dice_list.join(",")
  58. 3 then: 2 else: 1 result = (dice <= toughness ? '成功' : '失敗')
  59. 3 text = "ショック判定(ダメージ:#{damage}, 耐久力:#{toughness}) > (#{dice}[#{diceText}]) > #{result}"
  60. 3 return text
  61. end
  62. 1 def getStrikeLocationHuman(type)
  63. 10 typeName = ''
  64. 10 table = nil
  65. 10 case type
  66. when: 2 when 'U'
  67. 2 typeName = "命中部位(人型 上段)"
  68. 2 table = getStrikeLocationHumanUpperTable()
  69. when: 2 when 'D'
  70. 2 typeName = "命中部位(人型 下段)"
  71. 2 table = getStrikeLocationHumanDownTable()
  72. when: 6 when nil
  73. 6 typeName = "命中部位(人型 中段)"
  74. 6 table = getStrikeLocationHumanNormalTable()
  75. else: 0 else
  76. raise "unknow atak type #{type}"
  77. end
  78. 10 number = @randomizer.roll_once(100)
  79. 10 part = get_table_by_number(number, table)
  80. 10 part = getLocationSide(part, number)
  81. 10 part = getFaceLocation(part)
  82. 10 result = "#{typeName} > (#{number})#{part}"
  83. 10 return result
  84. end
  85. 1 def getLocationSide(part, number)
  86. 14 else: 5 then: 9 unless part =~ /^\*/
  87. 9 debug("part has NO side", part)
  88. 9 return part
  89. end
  90. 5 debug("part has side", part)
  91. 5 then: 1 else: 4 side = (number.odd? ? "左" : "右")
  92. 5 part.sub(/\*/, side)
  93. end
  94. 1 def getFaceLocation(part)
  95. 10 debug("getFaceLocation part", part)
  96. 10 else: 4 then: 6 unless part =~ /\+$/
  97. 6 debug("is NOT Face")
  98. 6 return part
  99. end
  100. 4 debug("is Face")
  101. table = [
  102. 4 [15, "顎"],
  103. [30, "*目"],
  104. [64, "*頬"],
  105. [80, "鼻"],
  106. [90, "*耳"],
  107. [100, "口"],
  108. ]
  109. 4 number = @randomizer.roll_once(100)
  110. 4 faceLocation = get_table_by_number(number, table)
  111. 4 debug("faceLocation", faceLocation)
  112. 4 debug("number", number)
  113. 4 faceLocation = getLocationSide(faceLocation, number)
  114. 4 result = part.sub(/\+$/, " > (#{number})#{faceLocation}")
  115. 4 return result
  116. end
  117. 1 def getStrikeLocationHumanUpperTable()
  118. table = [
  119. 2 [15, "頭部"],
  120. [30, "顔+"],
  121. [45, "首"],
  122. [57, "*肩"],
  123. [69, "*上腕"],
  124. [73, "*肘"],
  125. [81, "*前腕"],
  126. [85, "*手"],
  127. [95, "胸部"],
  128. [100, "腹部"],
  129. ]
  130. 2 return table
  131. end
  132. 1 def getStrikeLocationHumanNormalTable()
  133. table = [
  134. 6 [5, "頭部"],
  135. [10, "顔+"],
  136. [15, "首"],
  137. [27, "*肩"],
  138. [33, "*上腕"],
  139. [35, "*肘"],
  140. [39, "*前腕"],
  141. [43, "*手"],
  142. [60, "胸部"],
  143. [70, "腹部"],
  144. [74, "股間"],
  145. [80, "*臀部"],
  146. [88, "*腿"],
  147. [90, "*膝"],
  148. [96, "*脛"],
  149. [100, "*足"],
  150. ]
  151. 6 return table
  152. end
  153. 1 def getStrikeLocationHumanDownTable()
  154. table = [
  155. 2 [6, "*前腕"],
  156. [12, "*手"],
  157. [19, "胸部"],
  158. [29, "腹部"],
  159. [35, "股間"],
  160. [49, "*臀部"],
  161. [70, "*腿"],
  162. [78, "*膝"],
  163. [92, "*脛"],
  164. [100, "*足"],
  165. ]
  166. 2 return table
  167. end
  168. end
  169. end
  170. end

lib/bcdice/game_system/HatsuneMiku.rb

100.0% lines covered

96.0% branches covered

73 relevant lines. 73 lines covered and 0 lines missed.
25 total branches, 24 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class HatsuneMiku < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'HatsuneMiku'
  7. # ゲームシステム名
  8. 1 NAME = '初音ミクTRPG ココロダンジョン'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'はつねみくTRPGこころたんしよん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定(Rx±y@z>=t)
  14.  能力値のダイスごとに成功・失敗の判定を行います。
  15.  x:能力ランク(S,A~D)。数字指定で直接その個数のダイスが振れます
  16.  y:修正値。A+2 あるいは A++ のように表記。混在時は A++,+1 のように記述も可能
  17.  z:スペシャル最低値(省略:6) t:目標値(省略:4)
  18.   例) RA R2 RB+1 RC++ RD+,+2 RA>=5 RS-1@5>=6
  19.  結果はネイロを取得した残りで最大値を表示
  20. 例) RB
  21.  HatsuneMiku : (RB>=4) > [3,5] >
  22.   ネイロに3(青)を取得した場合 5:成功
  23.   ネイロに5(白)を取得した場合 3:失敗
  24. ・各種表
  25.  ファンブル表 FT/致命傷表 CWT/休憩表 BT/目標表 TT/関係表 RT
  26.  障害表 OT/リクエスト表 RQT/クロウル表 CLT/報酬表 RWT/悪夢表 NMT/情景表 ST
  27. ・キーワード表
  28.  ダーク DKT/ホット HKT/ラブ LKT/エキセントリック EKT/メランコリー MKT
  29. ・名前表 NT
  30.  コア別 ダーク DNT/ホット HNT/ラブ LNT/エキセントリック ENT/メランコリー MNT
  31. ・オトダマ各種表
  32.  性格表A OPA/性格表B OPB/趣味表 OHT/外見表 OLT/一人称表 OIT/呼び名表 OYT
  33.  リアクション表 ORT/出会い表 OMT
  34. INFO_MESSAGE_TEXT
  35. 1 def initialize(command)
  36. 57 super(command)
  37. 57 @d66_sort_type = D66SortType::ASC
  38. end
  39. 1 def eval_game_system_specific_command(command)
  40. 57 text = judgeRoll(command)
  41. 57 else: 29 then: 28 return text unless text.nil?
  42. 29 return roll_tables(command, TABLES)
  43. end
  44. 1 def judgeRoll(command)
  45. 57 else: 28 then: 29 return nil unless /^(R([A-DS]|\d+)([+\-\d,]*))(@(\d))?((>(=)?)([+\-\d]*))?(@(\d))?$/i =~ command
  46. 28 skillRank = Regexp.last_match(2)
  47. 28 modifyText = Regexp.last_match(3)
  48. 28 then: 20 else: 8 signOfInequality = (Regexp.last_match(7).nil? ? ">=" : Regexp.last_match(7))
  49. 28 then: 20 else: 8 targetText = (Regexp.last_match(9).nil? ? "4" : Regexp.last_match(9))
  50. 28 specialNum = Regexp.last_match(5)
  51. 28 specialNum ||= Regexp.last_match(11)
  52. 28 specialNum ||= 6
  53. 28 specialNum = specialNum.to_i
  54. 28 then: 24 else: 4 specialText = (specialNum == 6 ? "" : "@#{specialNum}")
  55. 28 modifyText = getChangedModifyText(modifyText)
  56. 28 commandText = "R#{skillRank}#{modifyText}"
  57. 28 rankDiceList = {"S" => 4, "A" => 3, "B" => 2, "C" => 1, "D" => 2}
  58. 28 diceCount = rankDiceList[skillRank]
  59. 28 then: 2 else: 26 diceCount = skillRank.to_i if skillRank =~ /^\d+$/
  60. 28 modify = ArithmeticEvaluator.eval(modifyText)
  61. 28 target = ArithmeticEvaluator.eval(targetText)
  62. 28 diceList = @randomizer.roll_barabara(diceCount, 6).sort
  63. 28 diceText = diceList.join(",")
  64. 28 then: 3 else: 25 diceList = [diceList.min] if skillRank == "D"
  65. 28 message = "(#{commandText}#{specialText}#{signOfInequality}#{targetText}) > [#{diceText}]#{modifyText} > "
  66. 28 then: 16 if diceList.length <= 1
  67. 16 dice = diceList.first
  68. 16 total = dice + modify
  69. 16 result = check_success(total, dice, signOfInequality, target, specialNum)
  70. 16 message += "#{total}:#{result}"
  71. else: 12 else
  72. 12 texts = []
  73. 12 diceList.each_with_index do |pickup_dice, index|
  74. 35 rests = diceList.clone
  75. 35 rests.delete_at(index)
  76. 35 dice = rests.max
  77. 35 total = dice + modify
  78. 35 result = check_success(total, dice, signOfInequality, target, specialNum)
  79. 35 colorList = ["黒", "赤", "青", "緑", "白", "任意"]
  80. 35 color = colorList[pickup_dice - 1]
  81. 35 texts << " ネイロに#{pickup_dice}(#{color})を取得した場合 #{total}:#{result}"
  82. end
  83. 12 texts.uniq!
  84. 12 message += "\n" + texts.join("\n")
  85. end
  86. 28 return message
  87. end
  88. 1 def getChangedModifyText(text)
  89. 28 modifyText = ""
  90. 28 values = text.split(/,/)
  91. 28 values.each do |value|
  92. 14 case value
  93. when: 2 when "++"
  94. 2 modifyText += "+2"
  95. when: 1 when "+"
  96. 1 modifyText += "+1"
  97. else: 11 else
  98. 11 modifyText += value
  99. end
  100. end
  101. 28 return modifyText
  102. end
  103. 1 def check_success(total_n, dice_n, signOfInequality, diff, special_n)
  104. 51 then: 0 else: 51 return "ファンブル" if dice_n == 1
  105. 51 then: 12 else: 39 return "スペシャル" if dice_n >= special_n
  106. 39 cmp_op = Normalize.comparison_operator(signOfInequality)
  107. 39 target_num = diff.to_i
  108. 39 then: 27 if total_n.send(cmp_op, target_num)
  109. 27 "成功"
  110. else: 12 else
  111. 12 "失敗"
  112. end
  113. end
  114. TABLES = {
  115. 1 "FT" => DiceTable::Table.new(
  116. "ファンブル表",
  117. "1D6",
  118. [
  119. "周囲から活気が失われる。黒以外のすべてのネイロを一つずつ減らす。",
  120. "仲間に迷惑をかけてしまう。自分以外のPC全員の【生命力】が1点減少する。",
  121. "この失敗は後に祟るかもしれない……。自分の【生命力】が1D6点減少する。",
  122. "ココロに疲労感が満ちていく。自分がストレスを1点受ける。",
  123. "1D6を振ること。そのPCのコアが、その出目が1ならダークに、2ならホットに、3ならラブに、4ならエキセントリックに、5ならメランコリーに変化する。6だった場合、コアは変化しない。",
  124. "ラッキー!特に何も起こらない"
  125. ]
  126. ),
  127. "CWT" => DiceTable::Table.new(
  128. "致命傷表",
  129. "1D6",
  130. [
  131. "絶望的な攻撃を受ける。そのキャラクターは強制退出になる。",
  132. "苦痛の悲鳴をあげ、無惨にも崩れ落ちる。そのキャラクターは行動不能になる。また、黒のネイロが一つ増える。",
  133. "オトクイの一撃で、あなたは吹き飛ばされてしまう。そのキャラクターは行動不能になる。また、分類が装備のナンバーにストレスを1点受ける。",
  134. "強烈な一撃を受けて気絶する。そのキャラクターは行動不能になる。",
  135. "意識はあるが、立ち上がることができない。そのキャラクターは行動不能になる。次のシーンにまだ【生命力】が0点だった場合、自動的に1点に回復する。",
  136. "奇跡的に踏みとどまり、持ちこたえる。【生命力】が1点になる。"
  137. ]
  138. ),
  139. "BT" => DiceTable::Table.new(
  140. "休憩表",
  141. "1D6",
  142. [
  143. "仲間との楽しい時間。自分の【想い人】のパトスを一つ回復する。",
  144. "これまでの冒険を思い返す。自分の【能力値】のパトスを一つ回復する。",
  145. "自分のオトダマと会話する。【協力者】のパトスか、ナンバーのパトスを一つ回復する。",
  146. "体をゆっくり休める。自分の【生命力】を2D6点回復する。望むなら、回復を行う前に、自分の【活力】を決め直してもよい。",
  147. "お、ラッキー!いいもの見つけた!自分のコインを1枚増やす。",
  148. "ノイズストアに接続できた。各PCは、自分の【頭脳】のダイスの数と同じ個数まで、アプリを購入できる。"
  149. ]
  150. ),
  151. "TT" => DiceTable::Table.new(
  152. "目標表",
  153. "1D6",
  154. [
  155. "悪意。PCの中でもっとも【生命力】の低いもの一人を目標に選ぶ。もっとも低い【生命力】の持ち主が複数いる場合、その中から、GMが自由に一人目標を選ぶ。",
  156. "狡猾。パラグラフ1〜5の中で、もっとも高い数値のパラグラフにいるPC一人を目標に選ぶ。全員が圏外にいる場合、圏外にいるPC全員を目標に選ぶ。",
  157. "堅実。PCの中で、その脅威の「判定欄」に書かれた能力値がもっとも低いランクのキャラクター一人を目標に選ぶ。もっとも低いランクのキャラクターが複数いる場合、その中から、もっとも低いモッドのキャラクター一人を目標に選ぶ。モッドも同じ値だった場合、GMが自由に一人目標を選ぶ。",
  158. "豪快。PCの中でもっとも高いランクの【武勇】の持ち主一人を目標に選ぶ。もっとも高いランクの持ち主が複数いる場合、その中から、もっとも高いモッドの持ち主一人を目標に選ぶ。モッドも同じ値だった場合、GMが自由に一人目標を選ぶ。",
  159. "単純。パラグラフ1〜5の中で、もっとも低い数値のパラグラフにいるPC一人を目標に選ぶ。全員が圏外にいる場合、圏外にいるPC全員を目標に選ぶ。",
  160. "乱戦。その脅威のいるパラグラフの数値と数値が1離れたパラグラフにいるPC全員を目標に選ぶ。そのパラグラフにPCがいなかった場合、GMが自由に一人目標を選ぶ。"
  161. ]
  162. ),
  163. "RT" => DiceTable::Table.new(
  164. "関係表",
  165. "1D6",
  166. [
  167. "恋心(プラス)/殺意(マイナス)",
  168. "同情(プラス)/侮蔑(マイナス)",
  169. "憧憬(プラス)/嫉妬(マイナス)",
  170. "信頼(プラス)/疑い(マイナス)",
  171. "共感(プラス)/不気味(マイナス)",
  172. "大切(プラス)/面倒(マイナス)"
  173. ]
  174. ),
  175. "OT" => DiceTable::Table.new(
  176. "障害表",
  177. "1D6",
  178. [
  179. "あなたのココロに大きな変化が訪れる。1D6を振ること。そのPCのコアが、その出目が1ならダークに、2ならホットに、3ならラブに、4ならエキセントリックに、5ならメランコリーに変化する。6だった場合、コアは変化しない。",
  180. "あなたは肉体的に大きなダメージを負う。1D6点のダメージを受ける。",
  181. "ノイズの助けを借りて問題を解決する。コインを1D6枚を支払う必要がある。コインを支払う場合、ほかのPCからコインを譲ってもらってもよい。支払いが足りなかった場合、その差額分だけ自分の【生命力】を減らす。",
  182. "大きな疲労感を感じる。ストレスを1点受ける。",
  183. "思わず時間をつかってしまう。【タイム】が1点減少する。",
  184. "場にイヤな気配が満ちていく。黒のネイロが一つ増える。"
  185. ]
  186. ),
  187. "RQT" => DiceTable::Table.new(
  188. "リクエスト表",
  189. "2D6",
  190. [
  191. "そのエリアの風景が、あなたの【情景】へと書き換えられていく。「お前の始まりの物語を語れ。お前はこの地で何を思った?」",
  192. "あなたは、そのエリアの風景の中に懐かしいものを見つけ、自分の罪を思い出した。「何を見た?なにを悔いている?」",
  193. "そのエリアの風景が、あなたのコアと同じ色に染まる。あなたは、その風景の中になりたい自分の姿を見つける。「それがお前の望みか?お前は未来に何を求める?」",
  194. "あなたの脳裏に、人物欄に書かれた人物一人のイメージが浮かぶ。その人物は何かを囁き、あなたのココロが傷ついた。「そいつは誰だ?一体何と言ったのだ?」",
  195. "あなたは、そのエリアの風景の中に奇妙なものを見つけ、恐怖した。「何を見た?なぜそれを恐れる?」",
  196. "そのエリアにココロダンジョンの持ち主が現れる。その人物は、お前に質問してくる。「私をどう思ってる?なぜ、私を助ける?」",
  197. "あなたのオトダマの姿が、あなたのよく知っている人物に変わる「その人物は誰だ?そいつをどう思っている?」",
  198. "そのエリアに、あなたの持つナンバーが響き渡る。「これがお前のウタか?そのウタの名はなんだ?」",
  199. "あなたのオトダマの姿が、あなたの好きな人物の姿に変わる。「それがお前が焦がれる人物か。そいつをどうしたい?」",
  200. "そのエリアの風景にあなたの日常が浮かび上がる。「お前は何をしている?その暮らしをどう思っている?」",
  201. "あなたの目の前に、あなたの死体が横たわっている。「お前を殺すものは何だ?お前は誰に殺される?」"
  202. ]
  203. ),
  204. "CLT" => DiceTable::Table.new(
  205. "クロウル表",
  206. "2D6",
  207. [
  208. "パスワードが抜き取られていた! 所持金が無くなっている! 自分のコインを3枚失う。",
  209. "過去に同様のオトクイと出会ったことのある人物に出会う。【技術】で判定を行う。成功すると、「特殊アプリの開発」を行うことができる(この間奏アクションには【タイム】は必要ない)。必要なコインは1枚少なくなる。",
  210. "近所にあるパワースポットを教えてもらう。【霊力】で判定を行う。成功すると、自分の【生命力】を【活力】の値だけ回復することができる。",
  211. "あなたのことを知る人物に出会う。どんな思い出話をしたのだろうか? この質問はリクエストとして扱う。",
  212. "プライベートの友人からメールが届いている。【愛】で判定を行う。成功すると、好きなNPCを協力者として設定することができる。判定に失敗すると苦情のメールだった。ストレスを1点受ける。",
  213. "ノイズメンバーから応援のメッセージをもらう。好きなネイロを1つ獲得する(この効果で。特定のネイロを7個以上にすることはできない)。",
  214. "美味しい食べ物屋さんに関する情報を教えてもらう。【日常】で判定を行う。成功すると、自分のストレスを1点回復できる。",
  215. "オトクイに関する情報を求めているノイズメンバーに出会う。公開されている脅威1つにつき、その情報をコイン1枚で売却できる。このイベントが2度以上起きた場合、すでに売却した脅威の情報を再び売ることはできない。",
  216. "試作アプリの試験者を募集している。好きなアプリ1つを獲得する。ただし、このアプリを使用するときサイコロを1個振ること。1か2が出ると、そのアプリは効果を発揮しない。セッション中に、試作アプリを使用しているとセッション終了時にレポートを提出できる。【頭脳】で判定を行う。成功すると、コインを1枚獲得できる。",
  217. "自分に関する悪口を見つける。そこには、どんな悪口が書かれていたのだろうか。 この質問は、リクエストとして扱う。",
  218. "同じ種類のオトダマと契約しているオトダマ使いと意気投合。このセッションの間、自分のナンバー1つを、修得可能な別のナンバーに変更することができる。",
  219. ]
  220. ),
  221. "RWT" => DiceTable::Table.new(
  222. "報酬表",
  223. "1D6",
  224. [
  225. "ノイズからオトクイ退治の報酬をもらうことができる。[倒したオトクイの本体のレベル]枚のコインを獲得する。",
  226. "ノイズにオトダマの情報を売ることができる。[自分の【頭脳】のダイスの数]枚のコインを獲得する。",
  227. "冒険を通じて因縁が芽生える。今回登場したキャラクターの中から一人を選ぶ。そのキャラクターを、自分の【想い人】にする。",
  228. "冒険を通じて絆が結ばれる。今回登場したNPCの中から一人を選ぶ。そのキャラクターを、自分の【協力者】にする。",
  229. "冒険の思い出が【ウタの欠片】になる。今回の冒険に登場した仲間、情景、出来事などなどから、キーワードを一つ選ぶ。そのキーワードを【ウタの欠片】のキーワード欄に追加する。",
  230. "戦いの経験が【ウタの欠片】になる。今回の冒険に登場した敵、情景、出来事などなどから、キーワードを一つ選ぶ。そのキーワードを【ウタの欠片】のキーワード欄に追加する。",
  231. ]
  232. ),
  233. "NMT" => DiceTable::Table.new(
  234. "悪夢表",
  235. "1D6",
  236. [
  237. "絶望のウタに知覚を遮断される。背後にオトクイの気配を感じたと思ったときは遅かった。卑劣な攻撃があなたを襲う。好きな能力値で判定を行う。失敗するとあなたのキャラクターは、オトナシとなり、二度と冒険に参加できない。",
  238. "絶望のウタに混じり、悲痛な叫びが聞こえてくる。ココロダンジョンの持ち主だろうか。あなたは、救えなかったのだ。【日常】で判定を行う。失敗すると、自分の能力値一つを選ぶ。次回のセッションは、その能力値にストレスを受けた状態で始まる。",
  239. "絶望のウタに混じり、オトクイの笑いがこだまする。それは嘲りの笑いだった。オトクイや仲間たち……何より自分への怒りがわき上がる。【日常】で判定を行う。失敗すると、自分の想い人への【想い】を一つ失う。",
  240. "絶望のウタの中に一人取り残される。誰もあなたに気づかない。孤独に耐えながら、何とか日常へ帰還したが……そのときの恐怖がぬぐえない。【日常】で判定を行う。失敗すると、次回のセッションは、自分の【生命力】の現在値が通常の半分(端数切り上げ)の状態で始まる。",
  241. "ココロダンジョンから帰還したあなたを待っていたのは、代わり映えのない日常だった。あなたが任務に失敗しても、世界は変わらない。なら、もう、あんな怖い目をする必要はないんじゃないか? 【日常】で判定を行う。失敗すると、自分のナンバー一つを選ぶ。次回のセッションは、そのナンバーにストレスを受けた状態で始まる。",
  242. "絶望のウタの中を必死で逃げ出した。背後から仲間の声が聞こえた気がする。しかし、あなたは振り返ることができなかった。【日常】で判定を行う。失敗すると、自分に対して【想い】を持っているPC一人を選び、その自分に対する【想い】が失われる。",
  243. ]
  244. ),
  245. "ST" => DiceTable::D66Table.new(
  246. "情景表",
  247. D66SortType::ASC,
  248. {
  249. 11 => "立ち並ぶ本棚の森",
  250. 12 => "夕日が差し込む教室",
  251. 13 => "鳴り止まない踏切",
  252. 14 => "ビルから見下ろした街並み",
  253. 15 => "二人で見た星空",
  254. 16 => "液晶画面に映る奇妙な光景",
  255. 22 => "ガラス窓に並ぶ雨だれ",
  256. 23 => "植物園の温室",
  257. 24 => "屋台が並ぶ祭りの風景",
  258. 25 => "陽炎が立ちのぼるアスファルト",
  259. 26 => "0時を示す時計の針",
  260. 33 => "無機質な白い天井",
  261. 34 => "暗闇に浮かび上がるヘッドライト",
  262. 35 => "後ろからついてくる野良猫",
  263. 36 => "一面の花畑",
  264. 44 => "あなたを見つめる大勢の観衆",
  265. 45 => "降り積もる雪",
  266. 46 => "古めかしい洋館の応接間",
  267. 55 => "おとぎ話に出てくるような森",
  268. 56 => "深夜のコンビニ",
  269. 66 => "誰もいない体育館"
  270. }
  271. ),
  272. "DKT" => DiceTable::D66Table.new(
  273. "ダーク・キーワード表",
  274. D66SortType::ASC,
  275. {
  276. 11 => "崩壊する楽園",
  277. 12 => "空に堕ちる",
  278. 13 => "優しい暴力",
  279. 14 => "沈黙の掟",
  280. 15 => "闇に溺れる",
  281. 16 => "こぼれ落ちた命",
  282. 22 => "行き止まりの絶望",
  283. 23 => "漆黒の翼",
  284. 24 => "眠れぬ夜",
  285. 25 => "避けられぬ運命",
  286. 26 => "斬り裂かれた景色",
  287. 33 => "からっぽな自分",
  288. 34 => "仮面の奥",
  289. 35 => "月光中毒",
  290. 36 => "昏い魔術",
  291. 44 => "……オブザデッド",
  292. 45 => "ココロを殺す",
  293. 46 => "感染する破滅",
  294. 55 => "愛の鎖",
  295. 56 => "残酷な真実",
  296. 66 => "デスゲーム"
  297. }
  298. ),
  299. "DNT" => DiceTable::D66Table.new(
  300. "ダーク・名前表",
  301. D66SortType::ASC,
  302. {
  303. 11 => "ダーク/濁、搦 ネロ/音呂、寝路",
  304. 12 => "クロト/黒斗、玄徒 ヤミ/夜美、闇",
  305. 13 => "ネクロ/根黒、寝喰 マコ/魔子、混乎",
  306. 14 => "カゲオ/影男、陰夫 オニコ/鬼子、隠忍呼",
  307. 15 => "アクタ/芥、悪太 ホタル/蛍、歩足",
  308. 16 => "マオウ/魔王、万凹 ミダラ/淫、美堕裸",
  309. 22 => "マミヤ/魔美也、狸夜 ジャミ/邪美、蛇実",
  310. 23 => "ドクロ/髑髏、毒炉 ヨミ/黄泉、詠",
  311. 24 => "マクラ/枕、真暗 サツキ/殺鬼、五月",
  312. 25 => "ゲドウ/外道、戯堂 サヤ/小夜、鞘",
  313. 26 => "ジゴク/地獄、慈極 ウマル/埋、兎丸",
  314. 33 => "エンド/怨人、終 ヨハネ/夜羽、世刎",
  315. 34 => "ノロイ/呪、鈍 カバネ/屍、椛音",
  316. 35 => "アクム/悪夢、飽夢 クサリ/腐、鎖",
  317. 36 => "バツ/罰、× ニエ/贄、沸",
  318. 44 => "ネガ/音我、願 リリス/璃々子、離里素",
  319. 45 => "ウツロ/虚、洞 ネタミ/妬美、寝多実",
  320. 46 => "ハジメ/始、創 ホロビ/滅、亡",
  321. 55 => "ザイン/罪印、沙陰 リンボ/淋墓、辺獄",
  322. 56 => "ハラワタ/腑、祓輪太 ユガミ/歪、由神",
  323. 66 => "イミ/忌、逝美 ムイミ/無意味、無為巳"
  324. }
  325. ),
  326. "HKT" => DiceTable::D66Table.new(
  327. "ホット・キーワード表",
  328. D66SortType::ASC,
  329. {
  330. 11 => "真夜中をぶっ壊す",
  331. 12 => "夢を打ち上げろ",
  332. 13 => "譲れない明日",
  333. 14 => "あふれ出す衝動",
  334. 15 => "獣を解き放て",
  335. 16 => "蒸発した涙",
  336. 22 => "高らかに叫べ",
  337. 23 => "負けられない戦い",
  338. 24 => "握りしめた拳",
  339. 25 => "疾走する青春",
  340. 26 => "ココロに従え",
  341. 33 => "がんばれ",
  342. 34 => "そのまま進め",
  343. 35 => "自分の旗",
  344. 36 => "抗い壊し突き進む",
  345. 44 => "咲き誇る情熱の花",
  346. 45 => "暑苦しい友情",
  347. 46 => "オレ色に染まれ",
  348. 55 => "世界に八つ当たり",
  349. 56 => "消せない炎",
  350. 66 => "オーバードライブ"
  351. }
  352. ),
  353. "HNT" => DiceTable::D66Table.new(
  354. "ホット・名前表",
  355. D66SortType::ASC,
  356. {
  357. 11 => "レッド/烈怒、煉集 アカネ/赤音、茜",
  358. 23 => "タケル/武、猛 ヒトミ/瞳、仁美",
  359. 36 => "ジョウ/情、丈 アオリ/煽、亜織",
  360. 12 => "アツシ/熱、純志 カンナ/神奈、柑菜",
  361. 24 => "グレン/紅蓮、九煉 ナツコ/夏子、懐子",
  362. 44 => "ロック/六句、麓 フォルテ/鳳流弖、彫照",
  363. 13 => "カケル/駆、賭 ハル/晴、春",
  364. 25 => "アラシ/嵐、荒 ヒカル/光、晃",
  365. 45 => "ヤマト/大和、岳斗 イサミ/伊佐美、勇美",
  366. 14 => "ガッツ/牙突、勝 アカリ/紅莉、明里",
  367. 26 => "エンジョウ/炎上、円定 コマチ/小町、小真知",
  368. 46 => "リュウセイ/流星、龍盛 ミライ/未来、美良依",
  369. 15 => "ケン/剣、拳 アスカ/明日香、飛鳥",
  370. 33 => "レツ/烈、裂 リズム/理澄、李珠夢",
  371. 55 => "イカル/怒、鵤 ヒマワリ/向日葵、火回",
  372. 16 => "ゴウ/豪、剛 ヒミコ/日美子、卑弥呼",
  373. 34 => "リキ/力、陸希 キョウカ/響歌、驚花",
  374. 56 => "ツトム/努、勉 ハナビ/花火、羽夏妃",
  375. 22 => "ヒイロ/火色、陽彩 アキラ/晶、爽",
  376. 35 => "ホムラ/焔、吠叢 カグヤ/輝夜、赫映",
  377. 66 => "レオ/伶央、獅王 マツリ/祭、茉莉"
  378. }
  379. ),
  380. "LKT" => DiceTable::D66Table.new(
  381. "ラブ・キーワード表",
  382. D66SortType::ASC,
  383. {
  384. 11 => "大人の恋",
  385. 12 => "ドキドキが止まらない",
  386. 13 => "つないだ手",
  387. 14 => "世界を敵に回しても",
  388. 15 => "重なる声",
  389. 16 => "君のためなら死ねる",
  390. 22 => "甘い口づけ",
  391. 23 => "まぶたをとじて",
  392. 24 => "キミとボク",
  393. 25 => "好きとか嫌いとか",
  394. 26 => "いつまでも",
  395. 33 => "抱きしめたい",
  396. 34 => "75億と1千五百万人愛してる",
  397. 35 => "自動的な恋",
  398. 36 => "会いたい",
  399. 44 => "伝えたいコトバ",
  400. 45 => "ありがとう",
  401. 46 => "時間を止めて",
  402. 55 => "大好き",
  403. 56 => "素敵な贈り物",
  404. 66 => "ビューティフルワールド"
  405. }
  406. ),
  407. "LNT" => DiceTable::D66Table.new(
  408. "ラブ・名前表",
  409. D66SortType::ASC,
  410. {
  411. 11 => "シアン/詩庵、思杏 アオイ/葵、蒼生",
  412. 12 => "ソナタ/奏名太、其方 イズミ/泉、出海",
  413. 13 => "ツナグ/繋、継 カレン/可憐、歌恋",
  414. 14 => "ミノル/実、稔 コイ/恋、鯉",
  415. 15 => "ユウ/優、悠 ラブ/良舞、羅步",
  416. 16 => "レイン/玲音、霊印 アマミ/甘味、天海",
  417. 22 => "ソウヤ/想夜、添也 フミ/文、芙美",
  418. 23 => "イトシ/糸糸、意俊 コイシ/恋志、小石",
  419. 24 => "エガオ/笑顔、描生 オモイ/想、念",
  420. 25 => "マコト/誠、真実 マナ/真菜、愛",
  421. 26 => "ユウリ/有理、悠里 ケイ/恵、佳",
  422. 33 => "チヒロ/千尋、茅紘 ウララ/麗、占",
  423. 34 => "トモ/友、杜望 ヒナ/雛、比奈",
  424. 35 => "ソラ/空、宙 ツユ/露、梅雨",
  425. 36 => "ユウダイ/雄大、優大 ノゾミ/望、希海",
  426. 44 => "ハグ/剥、抱 キス/喜好、口吻",
  427. 45 => "ショウタ/翔太、祥太 アイ/愛、藍",
  428. 46 => "ジュン/純、潤 ミサオ/美沙緒、操",
  429. 55 => "リョウ/涼、猟 イチズ/一途、意地図",
  430. 56 => "シグレ/時雨、紫暮 アオバ/青葉、碧羽",
  431. 66 => "ロミオ/路美雄、露澪 ロマン/浪漫、絽萬"
  432. }
  433. ),
  434. "EKT" => DiceTable::D66Table.new(
  435. "エキセントリック・キーワード表",
  436. D66SortType::ASC,
  437. {
  438. 11 => "シェフのきまぐれニルヴァーナ",
  439. 23 => "宇宙人とデート",
  440. 36 => "ぷるぷる",
  441. 12 => "おかず食べ過ぎ",
  442. 24 => "まいにち寝正月",
  443. 44 => "夜明けのツタンカーメン",
  444. 13 => "バイバイバイアグラ",
  445. 25 => "猫がにゃー",
  446. 45 => "半額の宴",
  447. 14 => "おふとん王国の攻防",
  448. 26 => "道草にがい",
  449. 46 => "超気持ちいいなにか",
  450. 15 => "ぐるぐるとクルクル",
  451. 33 => "ブシドーロック!サムライパンク!",
  452. 55 => "いあ!いあ!はすたあ!",
  453. 16 => "ゴリラの千年王国",
  454. 34 => "冷やしインド",
  455. 56 => "小学生に貯金で負けた",
  456. 22 => "くもん式フランケンシュタイナー",
  457. 35 => "生きててよかった",
  458. 66 => "秒速1ポロンクセマ"
  459. }
  460. ),
  461. "ENT" => DiceTable::D66Table.new(
  462. "エキセントリック・名前表",
  463. D66SortType::ASC,
  464. {
  465. 11 => "ライム/来夢、雷鵡 ミドリ/緑、美登里",
  466. 12 => "ランポ/乱歩、蘭舗 ビビリ/恐、美々裏",
  467. 13 => "シラズ/不知、調頭 ヒスイ/翡翠、陽彗",
  468. 14 => "ムウ/夢生、無 キノコ/茸、紀乃子",
  469. 15 => "ネコヒコ/猫彦、寝子日子 イヌコ/犬子、夷猫",
  470. 16 => "ダダ/駄々、蛇陀 キリコ/切子、霧湖",
  471. 22 => "イケメン/活面、逝麺 ラムネ/来夢音、螺旨",
  472. 23 => "キョウスケ/狂介、京助 ランマ/乱麻、爛漫",
  473. 24 => "ネジ/螺子、寝児 アリス/有栖、亜梨子",
  474. 25 => "マワル/回、環 タタミ/畳、多々実",
  475. 26 => "キュウ/球、Q ズキン/頭巾、厨琴",
  476. 33 => "サバン/沙蛮、裂卍 マニア/摩尼亜、間合",
  477. 34 => "カエル/帰、蛙 エリマキ/襟巻、絵里真希",
  478. 35 => "ナゾウ/謎宇、何造 カンノン/観音、疳暢",
  479. 36 => "イッキュウ/一休、逸宮 ミロク/弥勒、診録",
  480. 44 => "シュール/酒潤、終琉 カプリ/華降、噛布里",
  481. 45 => "キジン/奇人、鬼神 フシギ/不思議、節黄",
  482. 46 => "カブキ/歌舞伎、傾 メロン/芽論、女侖",
  483. 55 => "ジョーカー/冗歌、浄化 ピエロ/秘絵呂、道化師",
  484. 56 => "ウイロウ/外郎、初弄 マッチャ/抹茶、末耶",
  485. 66 => "ビックリ/吃驚、! ハテナ/果菜、?"
  486. }
  487. ),
  488. "MKT" => DiceTable::D66Table.new(
  489. "メランコリー・キーワード表",
  490. D66SortType::ASC,
  491. {
  492. 11 => "ごめんなさい",
  493. 12 => "甘い甘い逃避",
  494. 13 => "ひとりぼっち",
  495. 14 => "ズルい世界",
  496. 15 => "果たせなかった約束",
  497. 16 => "取り返しのつかない言葉",
  498. 22 => "いっそ死にたい",
  499. 23 => "置いてきた夢",
  500. 24 => "見あげた青空",
  501. 25 => "きみの嘘",
  502. 26 => "すれ違う言葉",
  503. 33 => "幸せだった昨日",
  504. 34 => "こんなはずじゃなかった",
  505. 35 => "別れてしまった二つの道",
  506. 36 => "また会えたらいいね",
  507. 44 => "ここではないどこか",
  508. 45 => "青春の終わり",
  509. 46 => "大好きだった膝の上",
  510. 55 => "誰かぼくをほめて",
  511. 56 => "高潔な裏切り",
  512. 66 => "ナルシズム"
  513. }
  514. ),
  515. "MNT" => DiceTable::D66Table.new(
  516. "メランコリー・名前表",
  517. D66SortType::ASC,
  518. {
  519. 11 => "ヴァイス/灰主、唄守 マシロ/真白、万代",
  520. 12 => "キズ/傷、疵 ダレカ/誰香、惰麗華",
  521. 13 => "ユレル/揺、遊玲流 エモ/絵萌、恵面",
  522. 14 => "オボロ/朧、憶露 ホノカ/仄、穂乃香",
  523. 15 => "メロ/夢露、芽朗 シズ/静、志津",
  524. 16 => "ヒイラギ/柊、氷刺木 カタミ/形見、片実",
  525. 22 => "リネン/理然、離念 スノウ/素皇、珠瑙",
  526. 23 => "セツナ/切、刹那 シノブ/偲、忍",
  527. 24 => "ナミダ/涙、波太 カスカ/霞歌、幽",
  528. 25 => "ムスビ/結、息日 カコ/過去、寡子",
  529. 26 => "ウソ/嘘、宇曽 アイカ/哀歌、愛香",
  530. 33 => "ペイン/閉音、病印 ツラミ/辛美、貫実",
  531. 34 => "ヨリミチ/寄道、頼道 シラユキ/白雪、知由樹",
  532. 35 => "ヒトリ/独、一人 オトナ/音鳴、乙菜",
  533. 36 => "スバル/昴、透遙 ハルカ/遥、晴香",
  534. 44 => "バイバイ/梅云、吠々 バニラ/香子蘭、芭韮",
  535. 45 => "トオル/透、通 リツ/律、慄",
  536. 46 => "タビ/旅、足袋 チギリ/契、千切",
  537. 55 => "サイゴ/彩吾、最期 サクラ/桜、咲良",
  538. 56 => "アワレ/憐、哀 ヒメイ/悲鳴、姫衣",
  539. 66 => "ヘヴン/戸聞、天国 ガラス/硝子、枯州"
  540. }
  541. ),
  542. "OPA" => DiceTable::D66Table.new(
  543. "オトダマ性格表A",
  544. D66SortType::ASC,
  545. {
  546. 11 => "さわやか",
  547. 12 => "単純",
  548. 13 => "目立ちたがり",
  549. 14 => "笑い上戸",
  550. 15 => "P大好き",
  551. 16 => "がんばり屋",
  552. 22 => "ひょうきん",
  553. 23 => "ほれっぽい",
  554. 24 => "勇敢",
  555. 25 => "好奇心旺盛",
  556. 26 => "優しい",
  557. 33 => "八方美人",
  558. 34 => "博愛",
  559. 35 => "感情的",
  560. 36 => "おしゃべり",
  561. 44 => "無鉄砲",
  562. 45 => "元気",
  563. 46 => "楽観的",
  564. 55 => "自信家",
  565. 56 => "自由",
  566. 66 => "好戦的"
  567. }
  568. ),
  569. "OPB" => DiceTable::D66Table.new(
  570. "オトダマ性格表B",
  571. D66SortType::ASC,
  572. {
  573. 11 => "悲観的",
  574. 12 => "大人しい",
  575. 13 => "臆病",
  576. 14 => "クール",
  577. 15 => "のんき",
  578. 16 => "マジメ",
  579. 22 => "夢想家",
  580. 23 => "常識人",
  581. 24 => "サイコ",
  582. 25 => "おおらか",
  583. 26 => "平和主義者",
  584. 33 => "慎重",
  585. 34 => "合理主義者",
  586. 35 => "無口",
  587. 36 => "照れ屋",
  588. 44 => "おひとよし",
  589. 45 => "なまけもの",
  590. 46 => "腰が低い",
  591. 55 => "疑い深い",
  592. 56 => "謙虚",
  593. 66 => "嘘つき"
  594. }
  595. ),
  596. "OHT" => DiceTable::D66Table.new(
  597. "オトダマ趣味表",
  598. D66SortType::ASC,
  599. {
  600. 11 => "散歩",
  601. 23 => "温泉",
  602. 36 => "オークション",
  603. 12 => "うわさ話",
  604. 24 => "ギャンブル",
  605. 44 => "パズル",
  606. 13 => "寝る",
  607. 25 => "動物",
  608. 45 => "占い",
  609. 14 => "読書",
  610. 26 => "アニメ",
  611. 46 => "焼き肉",
  612. 15 => "アイドル",
  613. 33 => "ガーデニング",
  614. 55 => "スポーツ観戦",
  615. 16 => "甘味",
  616. 34 => "漫画",
  617. 56 => "ゲーム",
  618. 22 => "飲み会",
  619. 35 => "ドラマ",
  620. 66 => "動画配信"
  621. }
  622. ),
  623. "OLT" => DiceTable::D66Table.new(
  624. "オトダマ外見表",
  625. D66SortType::ASC,
  626. {
  627. 11 => "デフォルト",
  628. 12 => "王子様/お姫様",
  629. 13 => "和装",
  630. 14 => "獣系",
  631. 15 => "ゴス",
  632. 16 => "眼鏡",
  633. 22 => "スポーツ",
  634. 23 => "軍服",
  635. 24 => "天使/悪魔の羽",
  636. 44 => "季節イベント",
  637. 25 => "学生服",
  638. 26 => "メガホン",
  639. 33 => "スポーツ系",
  640. 34 => "パンク",
  641. 35 => "フォーマル",
  642. 36 => "ジャージ",
  643. 45 => "白衣",
  644. 46 => "童話コス",
  645. 55 => "バニー",
  646. 56 => "水着",
  647. 66 => "戦隊コス"
  648. }
  649. ),
  650. "OIT" => DiceTable::Table.new(
  651. "オトダマ一人称表",
  652. "2D6",
  653. [
  654. "それがし",
  655. "おいら/あたい",
  656. "自分の名前",
  657. "おれ/あたし",
  658. "わたくし",
  659. "私",
  660. "ぼく/うち",
  661. "自分",
  662. "俺様/あたくし",
  663. "余/妾",
  664. "ミー"
  665. ]
  666. ),
  667. "OYT" => DiceTable::Table.new(
  668. "オトダマ呼び名表",
  669. "2D6",
  670. [
  671. "ユー",
  672. "(PCの名前)たん/きゅん",
  673. "同志(PCの名前)",
  674. "キミ",
  675. "(PCの名前)くん/ちゃん",
  676. "マスター",
  677. "(PCの名前)さん",
  678. "(PCの名前)様",
  679. "あなた",
  680. "(PCの名前)氏/女史",
  681. "(PCの名前)殿"
  682. ]
  683. ),
  684. "ORT" => DiceTable::Table.new(
  685. "リアクション表",
  686. "1D6",
  687. [
  688. "オトダマの表の性格を表すセリフ",
  689. "オトダマの裏の性格を表すセリフ",
  690. "PCを応援するセリフ",
  691. "PCをからかうセリフ",
  692. "趣味にまつわるセリフ",
  693. "攻撃を行うときのセリフ"
  694. ]
  695. ),
  696. "OMT" => DiceTable::Table.new(
  697. "出会い表",
  698. "2D6",
  699. [
  700. "名門オトダマ使い。あなたは、代々オトダマを操る一族に生まれました。あなたには、幼い頃から相棒となるオトダマがいます。あなたは、そのオトダマと共に育ちました。",
  701. "傷ついたオトダマ。ある日、あなたは傷ついたオトダマを発見しました。意識を失い、今にも消えそうなオトダマに触れると、オトダマは意識を取り戻し、あなたを恩人と慕うようになりました。",
  702. "見えないお友達。あなたは孤独な幼年期を過ごしてきました。そのとき、あなたを導いてくれたのが、あなたのオトダマです。オトダマは、あなたに他人のココロのウタを聞き、人々を助ける術を教えてくれました。",
  703. "再生。あなたはオトクイに自分のココロのウタを食べられました。オトダマ使いに憑依したオトクイが倒されたとき、自分のココロの中から新たなオトダマが生まれました。",
  704. "愛するココロ。あなたには、子どもの頃から大好きだったウタがありました。ある日、そのウタを口ずさんでいるとき、突然、後ろから拍手の音が聞こえました。振り向くと、そこにオトダマがいました。",
  705. "動画。あなたは、動画を通じて歌を聞くのが好きでした。あるとき、聞いたことのないような素敵なウタが聞こえてきたかと思うと、画面の向こうからオトダマが飛び出してきました。",
  706. "喪失。ある日、あなたは悲劇に見舞われました。そのとき、あなたはとても大切にしていた何かを失いました。その失ったものを補うかのように、あなたの側にオトダマが現れました。",
  707. "受け継がれるウタ。あなたのオトダマは、あなたが大好きだった人の相棒だったオトダマでした。しかし、その人は悲劇に出会い、あなたの元を去りました。そのとき、あなたにオトダマを託したのです。",
  708. "謎のメール。ある日、友人からあなたの元に一通のメールが送られてきました。そのメールを開くと、不思議な音楽が流れ出し、オトダマが現れました。その友人とは、それ以来、連絡がつきません。",
  709. "封印。ある日、あなたは古いレコード屋で一曲の音盤に出会います。その音盤を再生してみると、オトダマが現れました。そして、オトダマは「封印を解いてくれたお礼に、しばらく付き合ってあげる」と言ってきました。",
  710. "一目惚れ。以前、あなたは様々な楽曲を発表していました。すると、その楽曲に一目惚れしたと言って、あなたの元にオトダマが押しかけてきました。以来、そのオトダマに付きまとわれる毎日です。"
  711. ]
  712. ),
  713. }.freeze
  714. 1 register_prefix('R[A-DS]?', TABLES.keys)
  715. end
  716. end
  717. end

lib/bcdice/game_system/HeroScale.rb

99.61% lines covered

98.63% branches covered

516 relevant lines. 514 lines covered and 2 lines missed.
146 total branches, 144 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class HeroScale < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'HeroScale'
  7. # ゲームシステム名
  8. 1 NAME = '英雄の尺度'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'えいゆうのしやくと'
  11. 1 HELP_MESSAGE = <<~TEXT
  12. 同人TRPGシステム『英雄の尺度』用ダイスボット。
  13. 基本ルールブック+サプリメント対応。仮称は非対応。
  14. コマンド一覧は以下の通り。*添え字で内容は[]。†がついていたら添え字必須。
  15. 5hs4 超越
  16. 5hs4,b 肉体の超越
  17. 5hs4,s,* 科学の超越[†達成値への加算値]
  18. 5hs4,p 激情の超越
  19. 4hs6 加護
  20. 4hs6,s 選択の加護
  21. 4hs6,p 安寧の加護
  22. 4hs6,r 逆転の加護
  23. 3hs8,*,* 契約[奉納の出目1,奉納の出目2]
  24. 3hs8,a,*,* 享受の契約[†受諾出目1][†受諾出目2]
  25. 3hs8,e,* 収奪の契約[†取得出目]
  26. 3hs8,b 燃焼の契約
  27. 3hs8,o,*,* 奉納の契約[奉納の出目1,奉納の出目2]
  28. 2hs20 呪い
  29. 2hs20,r 歪曲の呪い
  30. 2hs20,c 崩壊の呪い
  31. 2hs20,d 破滅の呪い
  32. 3hs10 異物
  33. 3hs10,i 模造の異物
  34. 3hs10,m,* 混血の異物[追加振り基準出目(初期値10)]
  35. 3hs10,b,* 彼方の異物[追加振り停止基準値(初期値666)]
  36. 1hs60 報い
  37. 1hs60,d 堕落の報い
  38. 1hs60,o 忘却の報い
  39. 1hs60,s,* 封印の報い[出目への係数]
  40. 12hs2 同化
  41. 12hs2,m,*,*,*,*,*,*,*,* 怪物の同化[*d2,*d4,*d6,*d8,*d10,*d12,*d20,*d60]
  42. 12hs2,t,* [†2の枚数宣言]
  43. 12hs2,c,* 法則の同化[†1の枚数宣言]
  44. 1hs12 下位存在
  45. 2hs12 中位存在
  46. 2hs12,t 変遷の中位存在
  47. 2hs12,c 偶然の中位存在
  48. 2hs12,g,* 萌芽の上位存在[加算値]
  49. 3hs12 上位存在
  50. 3hs12,g 大神の上位存在
  51. 3hs12,h 神性の上位存在
  52. 3hs12,w 魔性の上位存在
  53. 3hs12,m 悪意の上位存在
  54. 3hs12,s,* 大罪の上位存在[†確定する目標値]
  55. 3hs12,d 破壊の上位存在
  56. 3hs12,a 懊悩の上位存在
  57. 3hs12,o 試練の上位存在
  58. 3hs12,c 創造の上位存在
  59. 3hs12,e 元素の上位存在
  60. *hs* 乗算ロール
  61. TEXT
  62. 1 register_prefix('\d+HS\d+')
  63. 1 def eval_game_system_specific_command(command)
  64. 90 return select_origin(command)
  65. end
  66. 1 private
  67. 1 def select_origin(command)
  68. 90 order = command.split(",")
  69. 90 case order[0]
  70. when: 9 when "5HS4"
  71. 9 return origin_great(order)
  72. when: 5 when "4HS6"
  73. 5 return origin_protection(order)
  74. when: 9 when "3HS8"
  75. 9 return origin_vow(order)
  76. when: 7 when "2HS20"
  77. 7 return origin_curse(order)
  78. when: 11 when "3HS10"
  79. 11 return origin_stranger(order)
  80. when: 9 when "1HS60"
  81. 9 return origin_karma(order)
  82. when: 11 when "12HS2"
  83. 11 return origin_absorption(order)
  84. when: 1 when "1HS12"
  85. 1 return origin_normal()
  86. when: 6 when "2HS12"
  87. 6 return origin_unique(order)
  88. when: 21 when "3HS12"
  89. 21 return origin_omnipotent(order)
  90. else: 1 else
  91. 1 message = order[0]
  92. 1 dice = order[0].rpartition("HS")
  93. 1 then: 1 if dice.length > 2 && dice[0] =~ /^\d+$/ && dice[2] =~ /^\d+$/
  94. 1 natural_result = @randomizer.roll_barabara(dice[0].to_i, dice[2].to_i)
  95. 1 total = results_multiplication(natural_result)
  96. 1 message += " > #{total}[#{natural_result.join(',')}]"
  97. 1 return message
  98. else: 0 else
  99. return nil
  100. end
  101. end
  102. end
  103. # 超越
  104. 1 def origin_great(order)
  105. 9 natural_result = @randomizer.roll_barabara(5, 4)
  106. 9 case order[1]
  107. when: 1 when "P"
  108. 1 message = fate_passion(natural_result)
  109. when: 5 when "S"
  110. 5 message = fate_science(natural_result, order)
  111. when: 2 when "B"
  112. 2 message = fate_body(natural_result)
  113. else: 1 else
  114. 1 total = results_multiplication(natural_result)
  115. 1 message = "超越 > #{total}[#{natural_result.join(',')}]"
  116. end
  117. 9 return message
  118. end
  119. 1 def fate_passion(natural_result)
  120. 1 modified_result = []
  121. 1 number_of_1 = natural_result.count(1)
  122. 1 natural_result.each do |result|
  123. 5 modified_result << result + number_of_1
  124. end
  125. 1 subtotal = results_multiplication(natural_result)
  126. 1 total = results_multiplication(modified_result)
  127. 1 message = "激情の超越 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  128. 1 return message
  129. end
  130. 1 def fate_science(natural_result, order)
  131. 5 subtotal = results_multiplication(natural_result)
  132. 5 then: 3 if order.length > 2 && order[2] =~ /^\d+$/
  133. 3 then: 2 if order[2].to_i < 1024
  134. 2 total = subtotal + order[2].to_i
  135. 2 message = "科学の超越 > #{subtotal}[#{natural_result.join(',')}] > #{total}"
  136. 2 then: 1 else: 1 if total > 1023
  137. 1 message += "(科学臨界)"
  138. end
  139. else: 1 else
  140. 1 message = "エラー:科学力が1024を超えています。"
  141. end
  142. else: 2 else
  143. 2 message = "エラー:科学力を設定してください。"
  144. end
  145. 5 return message
  146. end
  147. 1 def fate_body(natural_result)
  148. 2 modified_result = natural_result.dup
  149. 2 modified_result.each do |result|
  150. 13 then: 3 else: 10 if result == 4
  151. 3 modified_result << @randomizer.roll_once(4)
  152. end
  153. end
  154. 2 subtotal = results_multiplication(natural_result)
  155. 2 total = results_multiplication(modified_result)
  156. 2 message = "肉体の超越 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  157. 2 return message
  158. end
  159. # 加護
  160. 1 def origin_protection(order)
  161. 5 natural_result = @randomizer.roll_barabara(4, 6)
  162. 5 case order[1]
  163. when: 1 when "R"
  164. 1 message = fate_reversal(natural_result)
  165. when: 1 when "P"
  166. 1 message = fate_peace(natural_result)
  167. when: 2 when "S"
  168. 2 message = fate_choice(natural_result)
  169. else: 1 else
  170. 1 total = results_multiplication(natural_result)
  171. 1 message = "加護 > #{total}[#{natural_result.join(',')}]"
  172. end
  173. 5 return message
  174. end
  175. 1 def fate_reversal(natural_result)
  176. 1 modified_result = []
  177. 1 natural_result.each do |result|
  178. 4 then: 3 else: 1 if result < 4
  179. 3 result = 7 - result
  180. end
  181. 4 modified_result << result
  182. end
  183. 1 subtotal = results_multiplication(natural_result)
  184. 1 total = results_multiplication(modified_result)
  185. 1 message = "逆転の加護 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  186. 1 return message
  187. end
  188. 1 def fate_peace(natural_result)
  189. 1 subtotal = results_multiplication(natural_result)
  190. 1 total = subtotal + 250
  191. 1 message = "安寧の加護 > #{subtotal}[#{natural_result.join(',')}] > #{total}"
  192. 1 return message
  193. end
  194. 1 def fate_choice(natural_result)
  195. 2 modified_result = natural_result.dup
  196. 2 modified_result.concat(@randomizer.roll_barabara(3, 6))
  197. 2 even_total = 1
  198. 2 odd_total = 1
  199. 2 modified_result.each do |result|
  200. 14 then: 4 if result.even?
  201. 4 even_total *= result
  202. else: 10 else
  203. 10 odd_total *= result
  204. end
  205. end
  206. 2 then: 1 if even_total > odd_total
  207. 1 total = even_total
  208. else: 1 else
  209. 1 total = odd_total
  210. end
  211. 2 subtotal = results_multiplication(natural_result)
  212. 2 message = "選択の加護 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  213. 2 return message
  214. end
  215. # 契約
  216. 1 def origin_vow(order)
  217. 9 natural_result = @randomizer.roll_barabara(3, 8)
  218. 9 case order[1]
  219. when: 2 when "O"
  220. 2 message = fate_offering(natural_result, order)
  221. when: 1 when "B"
  222. 1 message = fate_burning(natural_result)
  223. when: 2 when "E"
  224. 2 message = fate_exploitation(natural_result, order)
  225. when: 2 when "A"
  226. 2 message = fate_acceptance(natural_result, order)
  227. else: 2 else
  228. 2 subtotal = results_multiplication(natural_result)
  229. 2 then: 1 if order.length > 2 && order[1] =~ /^\d+$/ && order[2] =~ /^\d+$/
  230. 1 modified_result = natural_result.dup
  231. 1 modified_result << order[1].to_i
  232. 1 modified_result << order[2].to_i
  233. 1 total = results_multiplication(modified_result)
  234. 1 message = "契約 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  235. else: 1 else
  236. 1 message = "契約 > #{subtotal}[#{natural_result.join(',')}]"
  237. end
  238. end
  239. 9 return message
  240. end
  241. 1 def fate_offering(natural_result, order)
  242. 2 subtotal = results_multiplication(natural_result)
  243. 2 then: 1 if order.length > 3 && order[2] =~ /^\d+$/ && order[3] =~ /^\d+$/
  244. 1 modified_result = natural_result.dup
  245. 1 modified_result << order[2].to_i
  246. 1 modified_result << order[3].to_i
  247. 1 total = results_multiplication(modified_result)
  248. 1 message = "奉納の契約 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  249. else: 1 else
  250. 1 message = "奉納の契約 > #{subtotal}[#{natural_result.join(',')}]"
  251. end
  252. 2 offering_result = natural_result.dup
  253. 2 offering_result.sort!.reverse!.shift(1)
  254. 2 message += "(奉納:#{offering_result.join(',')})"
  255. 2 return message
  256. end
  257. 1 def fate_burning(natural_result)
  258. 1 subtotal = results_multiplication(natural_result)
  259. 1 total = subtotal * 6
  260. 1 message = "燃焼の契約 > #{subtotal}[#{natural_result.join(',')}] > #{total}"
  261. 1 return message
  262. end
  263. 1 def fate_exploitation(natural_result, order)
  264. 2 subtotal = results_multiplication(natural_result)
  265. 2 then: 1 if order.length > 2 && order[2] =~ /^\d+$/
  266. 1 modified_result = natural_result.dup
  267. 1 modified_result[modified_result.index(modified_result.min)] = order[2].to_i
  268. 1 total = results_multiplication(modified_result)
  269. 1 message = "収奪の契約 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  270. else: 1 else
  271. 1 message = "エラー:収奪数を指定してください。"
  272. end
  273. 2 return message
  274. end
  275. 1 def fate_acceptance(natural_result, order)
  276. 2 subtotal = results_multiplication(natural_result)
  277. 2 then: 1 if order.length > 3 && order[2] =~ /^\d+$/ && order[3] =~ /^\d+$/
  278. 1 change_result = natural_result.min(2)
  279. 1 modified_result = natural_result.dup
  280. 1 modified_result[modified_result.index(change_result[0])] = order[2].to_i
  281. 1 modified_result[modified_result.index(change_result[1])] = order[3].to_i
  282. 1 total = results_multiplication(modified_result)
  283. 1 message = "享受の契約 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  284. else: 1 else
  285. 1 message = "エラー:享受数を指定してください。"
  286. end
  287. 2 return message
  288. end
  289. # 呪い
  290. 1 def origin_curse(order)
  291. 7 natural_result = @randomizer.roll_barabara(2, 20)
  292. 7 case order[1]
  293. when: 1 when "R"
  294. 1 message = fate_ruin(natural_result)
  295. when: 3 when "C"
  296. 3 message = fate_collapse(natural_result)
  297. when: 2 when "D"
  298. 2 message = fate_distortion(natural_result)
  299. else: 1 else
  300. 1 total = results_multiplication(natural_result)
  301. 1 message = "呪い > #{total}[#{natural_result.join(',')}]"
  302. end
  303. 7 return message
  304. end
  305. 1 def fate_ruin(natural_result)
  306. 1 modified_result = natural_result.dup
  307. 1 modified_result.concat(@randomizer.roll_barabara(2, 20))
  308. 1 total = 1
  309. 1 modified_result.each do |result|
  310. 4 then: 1 else: 3 if result > 10
  311. 1 total *= result
  312. end
  313. end
  314. 1 subtotal = results_multiplication(natural_result)
  315. 1 message = "破滅の呪い > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  316. 1 return message
  317. end
  318. 1 def fate_collapse(natural_result)
  319. 3 modified_result = natural_result.dup
  320. 3 collapse_result = result_raoundup(natural_result[natural_result.index(natural_result.max)])
  321. 3 then: 1 if modified_result[0] == modified_result[1]
  322. 1 modified_result[0] = collapse_result
  323. 1 modified_result[1] = collapse_result
  324. 1 modified_result << collapse_result
  325. 1 modified_result << collapse_result
  326. else: 2 else
  327. 2 modified_result[natural_result.index(natural_result.max)] = collapse_result
  328. 2 modified_result.insert(natural_result.index(natural_result.max), collapse_result)
  329. end
  330. 3 subtotal = results_multiplication(natural_result)
  331. 3 total = results_multiplication(modified_result)
  332. 3 message = "崩壊の呪い > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  333. 3 return message
  334. end
  335. 1 def fate_distortion(natural_result)
  336. 2 modified_result = natural_result.dup
  337. 2 then: 1 if modified_result[0] == modified_result[1]
  338. 1 modified_result[0] += 13
  339. 1 modified_result[1] += 13
  340. else: 1 else
  341. 1 modified_result[natural_result.index(natural_result.min)] += 13
  342. end
  343. 2 subtotal = results_multiplication(natural_result)
  344. 2 total = results_multiplication(modified_result)
  345. 2 message = "歪曲の呪い > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  346. 2 return message
  347. end
  348. # 異物
  349. 1 def origin_stranger(order)
  350. 11 natural_result = @randomizer.roll_barabara(3, 10)
  351. 11 natural_result = stranger_effection(natural_result)
  352. 11 case order[1]
  353. when: 2 when "I"
  354. 2 message = fate_imitation(natural_result)
  355. when: 3 when "M"
  356. 3 message = fate_mixed(natural_result, order)
  357. when: 5 when "B"
  358. 5 message = fate_beyond(natural_result, order)
  359. else: 1 else
  360. 1 total = results_multiplication(natural_result)
  361. 1 message = "異物 > #{total}[#{natural_result.join(',')}]"
  362. end
  363. 11 return message
  364. end
  365. 1 def fate_imitation(natural_result)
  366. 2 modified_result = natural_result.dup
  367. 2 modified_result.sort!
  368. 2 then: 1 else: 1 modified_result[0] = (modified_result[0] + modified_result[1] * 10) == 0 ? 100 : (modified_result[0] + modified_result[1] * 10)
  369. 2 modified_result[1] = modified_result[2]
  370. 2 modified_result.delete_at(2)
  371. 2 subtotal = results_multiplication(natural_result)
  372. 2 total = results_multiplication(modified_result)
  373. 2 message = "模造の異物 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  374. 2 return message
  375. end
  376. 1 def fate_mixed(natural_result, order)
  377. 3 subtotal = results_multiplication(natural_result)
  378. 3 then: 2 if order.length > 2 && order[2] =~ /^\d+$/
  379. 2 mixed_score = order[2].to_i
  380. else: 1 else
  381. 1 mixed_score = 1
  382. end
  383. 3 modified_result = natural_result.dup
  384. 3 then: 1 if mixed_score <= natural_result.min
  385. 1 modified_result << @randomizer.roll_once(12)
  386. 1 total = results_multiplication(modified_result)
  387. 1 message = "混血の異物 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}](追加振り)"
  388. else: 2 else
  389. 2 modified_result[natural_result.index(natural_result.min)] = 10
  390. 2 total = results_multiplication(modified_result)
  391. 2 message = "混血の異物 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}](10置換)"
  392. end
  393. 3 return message
  394. end
  395. 1 def fate_beyond(natural_result, order)
  396. 5 modified_result = natural_result.dup
  397. 5 subtotal = results_multiplication(natural_result)
  398. 5 total = subtotal
  399. 5 beyond_limit = 666
  400. 5 then: 2 else: 3 if order.length > 2 && order[2] =~ /^\d+$/ && (order[2].to_i < 666)
  401. 2 beyond_limit = order[2].to_i
  402. end
  403. 5 body: 1 while total != 0 && total <= beyond_limit
  404. 1 modified_result << @randomizer.roll_d9
  405. 1 total = results_multiplication(modified_result)
  406. end
  407. 5 message = "彼方の異物 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  408. 5 return message
  409. end
  410. # 報い
  411. 1 def origin_karma(order)
  412. 9 natural_result = @randomizer.roll_barabara(1, 60)
  413. 9 case order[1]
  414. when: 3 when "D"
  415. 3 message = fate_depravity(natural_result)
  416. when: 1 when "O"
  417. 1 message = fate_oblivion(natural_result)
  418. when: 4 when "S"
  419. 4 message = fate_sealed(natural_result, order)
  420. else: 1 else
  421. 1 total = results_multiplication(natural_result)
  422. 1 message = "報い > #{total}[#{natural_result.join(',')}]"
  423. end
  424. 9 return message
  425. end
  426. 1 def fate_depravity(natural_result)
  427. 3 subtotal = results_multiplication(natural_result)
  428. 3 modified_result = natural_result.dup
  429. 3 depravity_num1 = natural_result[0] % 10
  430. 3 depravity_num10 = natural_result[0] / 10
  431. 3 then: 2 else: 1 if depravity_num10 > 1
  432. 2 modified_result << depravity_num10
  433. end
  434. 3 then: 2 else: 1 if depravity_num1 > 1
  435. 2 modified_result << depravity_num1
  436. end
  437. 3 total = results_multiplication(modified_result)
  438. 3 message = "堕落の報い > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  439. 3 return message
  440. end
  441. 1 def fate_oblivion(natural_result)
  442. 1 modified_result = natural_result.dup
  443. 1 modified_result << @randomizer.roll_once(60)
  444. 1 subtotal = results_multiplication(natural_result)
  445. 1 total = results_multiplication(modified_result) / 2
  446. 1 message = "忘却の報い > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  447. 1 return message
  448. end
  449. 1 def fate_sealed(natural_result, order)
  450. 4 modified_result = natural_result.dup
  451. 4 subtotal = results_multiplication(natural_result)
  452. 4 sealed_break = 1
  453. 4 then: 2 else: 2 if order.length > 2 && order[2] =~ /^\d+$/
  454. 2 sealed_break = order[2].to_i
  455. end
  456. 4 modified_result[0] *= sealed_break
  457. 4 total = subtotal * sealed_break
  458. 4 message = "封印の報い > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  459. 4 then: 1 if total <= 30
  460. 1 sealed_break *= 4
  461. 1 else: 3 message += "(封印解除成功:#{sealed_break})"
  462. 3 then: 2 elsif total <= 60
  463. 2 sealed_break *= 2
  464. 2 message += "(封印解除成功:#{sealed_break})"
  465. else: 1 else
  466. 1 message += "(封印解除失敗:#{sealed_break})"
  467. end
  468. 4 return message
  469. end
  470. # 同化
  471. 1 def origin_absorption(order)
  472. 11 natural_result = @randomizer.roll_barabara(12, 2)
  473. 11 case order[1]
  474. when: 5 when "M"
  475. 5 message = fate_monster(natural_result, order)
  476. when: 3 when "T"
  477. 3 message = fate_treasure(natural_result, order)
  478. when: 2 when "C"
  479. 2 message = fate_concept(natural_result, order)
  480. else: 1 else
  481. 1 total = results_multiplication(natural_result)
  482. 1 message = "同化 > #{total}[#{natural_result.join(',')}]"
  483. end
  484. 11 return message
  485. end
  486. 1 def fate_monster(_natural_result, order)
  487. 5 modified_result = []
  488. 5 then: 4 if order.length > 9 && order[2] =~ /^\d+$/ && order[3] =~ /^\d+$/ && order[4] =~ /^\d+$/ && order[5] =~ /^\d+$/ && order[6] =~ /^\d+$/ && order[7] =~ /^\d+$/ && order[8] =~ /^\d+$/ && order[9] =~ /^\d+$/
  489. 4 then: 3 else: 1 if order[2].to_i > 0
  490. 3 modified_result.concat(@randomizer.roll_barabara(order[2].to_i, 2))
  491. end
  492. 4 then: 3 else: 1 if order[3].to_i > 0
  493. 3 modified_result.concat(@randomizer.roll_barabara(order[3].to_i, 4))
  494. end
  495. 4 then: 1 else: 3 if order[4].to_i > 0
  496. 1 modified_result.concat(@randomizer.roll_barabara(order[4].to_i, 6))
  497. end
  498. 4 then: 2 else: 2 if order[5].to_i > 0
  499. 2 modified_result.concat(@randomizer.roll_barabara(order[5].to_i, 8))
  500. end
  501. 4 count_of_10 = order[6].to_i
  502. 4 body: 1 while count_of_10 > 0
  503. 1 modified_result << @randomizer.roll_d9
  504. 1 count_of_10 -= 1
  505. end
  506. 4 then: 1 else: 3 if order[7].to_i > 0
  507. 1 modified_result.concat(@randomizer.roll_barabara(order[7].to_i, 12))
  508. end
  509. 4 then: 1 else: 3 if order[8].to_i > 0
  510. 1 modified_result.concat(@randomizer.roll_barabara(order[8].to_i, 20))
  511. end
  512. 4 then: 1 else: 3 if order[9].to_i > 0
  513. 1 modified_result.concat(@randomizer.roll_barabara(order[9].to_i, 60))
  514. end
  515. 4 total = results_multiplication(modified_result)
  516. 4 subtotal = modified_result.sum
  517. 4 message = "怪物の同化 > #{total}[#{modified_result.join(',')}] 浸蝕値:#{subtotal}"
  518. 4 then: 2 else: 2 if [2, 4, 6, 8, 10, 12, 20, 60].include?(subtotal)
  519. 2 message += "(変異進行)"
  520. end
  521. 4 then: 2 else: 2 if modified_result.include?(1)
  522. 2 message += "(人間性喪失)"
  523. end
  524. else: 1 else
  525. 1 message = "エラー:変異状態を指定してください。"
  526. end
  527. 5 return message
  528. end
  529. 1 def fate_treasure(natural_result, order)
  530. 3 modified_result = natural_result.dup
  531. 3 subtotal = results_multiplication(natural_result)
  532. 3 total = subtotal
  533. 3 then: 2 if order.length > 2 && order[2] =~ /^\d+$/
  534. 2 treasure_point = order[2].to_i
  535. 2 then: 1 if modified_result.count(2) >= treasure_point
  536. 1 total *= treasure_point
  537. 1 message = "秘宝の同化 > #{subtotal}[#{natural_result.join(',')}] > #{total}(同調成功)"
  538. else: 1 else
  539. 1 message = "秘宝の同化 > #{subtotal}[#{natural_result.join(',')}] > #{total}(同調失敗)"
  540. end
  541. else: 1 else
  542. 1 message = "エラー:解放率を指定してください。"
  543. end
  544. 3 return message
  545. end
  546. 1 def fate_concept(natural_result, order)
  547. 2 modified_result = natural_result.dup
  548. 2 subtotal = results_multiplication(natural_result)
  549. 2 then: 1 if order.length > 2 && order[2] =~ /^\d+$/
  550. 1 existence_scale = order[2].to_i
  551. 1 then: 0 else: 1 if existence_scale > 12
  552. existence_scale = 12
  553. end
  554. 1 modified_result.fill(2, 0, existence_scale)
  555. 1 total = results_multiplication(modified_result)
  556. 1 message = "概念の同化 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  557. else: 1 else
  558. 1 message = "エラー:事象強度を指定してください。"
  559. end
  560. 2 return message
  561. end
  562. # 下位存在
  563. 1 def origin_normal()
  564. 1 natural_result = @randomizer.roll_barabara(1, 12)
  565. 1 total = results_multiplication(natural_result)
  566. 1 message = "下位存在 > #{total}[#{natural_result.join(',')}]"
  567. 1 return message
  568. end
  569. # 中位存在
  570. 1 def origin_unique(order)
  571. 6 natural_result = @randomizer.roll_barabara(2, 12)
  572. 6 case order[1]
  573. when: 2 when "G"
  574. 2 message = fate_growth(natural_result, order)
  575. when: 1 when "T"
  576. 1 message = fate_transition(natural_result)
  577. when: 2 when "C"
  578. 2 message = fate_chance(natural_result)
  579. else: 1 else
  580. 1 total = results_multiplication(natural_result)
  581. 1 message = "中位存在 > #{total}[#{natural_result.join(',')}]"
  582. end
  583. 6 return message
  584. end
  585. 1 def fate_growth(natural_result, order)
  586. 2 subtotal = results_multiplication(natural_result)
  587. 2 total = subtotal
  588. 2 then: 1 if order.length > 2 && order[2] =~ /^\d+$/
  589. 1 total += order[2].to_i
  590. 1 message = "萌芽の中位存在 > #{subtotal}[#{natural_result.join(',')}] > #{total}"
  591. else: 1 else
  592. 1 message = "萌芽の中位存在 > #{subtotal}[#{natural_result.join(',')}]"
  593. end
  594. 2 growth_level = order[2].to_i + 50
  595. 2 message += "(成長段階:#{growth_level})"
  596. 2 return message
  597. end
  598. 1 def fate_transition(natural_result)
  599. 1 modified_result = natural_result.dup
  600. 1 modified_result << @randomizer.roll_d9
  601. 1 subtotal = results_multiplication(natural_result)
  602. 1 total = results_multiplication(modified_result)
  603. 1 message = "変遷の中位存在 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  604. 1 return message
  605. end
  606. 1 def fate_chance(natural_result)
  607. 2 modified_result = natural_result.dup
  608. 2 subtotal = results_multiplication(natural_result)
  609. 2 total = results_multiplication(modified_result)
  610. 2 then: 1 if modified_result[0] == modified_result[1]
  611. 1 total *= 24
  612. 1 message = "偶然の中位存在 > #{subtotal}[#{natural_result.join(',')}] > #{total}"
  613. else: 1 else
  614. 1 message = "偶然の中位存在 > #{subtotal}[#{natural_result.join(',')}]"
  615. end
  616. 2 return message
  617. end
  618. # 上位存在
  619. 1 def origin_omnipotent(order)
  620. 21 natural_result = @randomizer.roll_barabara(3, 12)
  621. 21 case order[1]
  622. when: 1 when "G"
  623. 1 message = fate_god(natural_result)
  624. when: 1 when "H"
  625. 1 message = fate_holy(natural_result)
  626. when: 1 when "W"
  627. 1 message = fate_wicked(natural_result)
  628. when: 1 when "M"
  629. 1 message = fate_malice(natural_result)
  630. when: 6 when "S"
  631. 6 message = fate_sin(natural_result, order)
  632. when: 1 when "D"
  633. 1 message = fate_destruction(natural_result)
  634. when: 2 when "A"
  635. 2 message = fate_anguish(natural_result)
  636. when: 2 when "O"
  637. 2 message = fate_ordeal(natural_result)
  638. when: 3 when "C"
  639. 3 message = fate_creation(natural_result)
  640. when: 1 when "E"
  641. 1 message = fate_element()
  642. else: 2 else
  643. 2 total = results_multiplication(natural_result)
  644. 2 message = "上位存在 > #{total}[#{natural_result.join(',')}]"
  645. end
  646. 21 return message
  647. end
  648. 1 def fate_god(natural_result)
  649. 1 modified_result = []
  650. 1 natural_result.each do |result|
  651. 3 modified_result << result + 3
  652. end
  653. 1 subtotal = results_multiplication(natural_result)
  654. 1 total = results_multiplication(modified_result)
  655. 1 message = "大神の上位存在 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  656. 1 return message
  657. end
  658. 1 def fate_holy(natural_result)
  659. 1 modified_result = []
  660. 1 natural_result.each do |result|
  661. 3 modified_result << result + 1
  662. end
  663. 1 subtotal = results_multiplication(natural_result)
  664. 1 total = results_multiplication(modified_result)
  665. 1 message = "神性の上位存在 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  666. 1 return message
  667. end
  668. 1 def fate_wicked(natural_result)
  669. 1 subtotal = results_multiplication(natural_result)
  670. 1 total = subtotal + 120
  671. 1 message = "魔性の上位存在 > #{subtotal}[#{natural_result.join(',')}] > #{total}"
  672. 1 return message
  673. end
  674. 1 def fate_malice(natural_result)
  675. 1 subtotal = results_multiplication(natural_result)
  676. 1 total = subtotal * 2
  677. 1 message = "悪意の上位存在 > #{subtotal}[#{natural_result.join(',')}] > #{total}"
  678. 1 return message
  679. end
  680. 1 def fate_sin(natural_result, order)
  681. 6 subtotal = results_multiplication(natural_result)
  682. 6 total = subtotal
  683. 6 then: 5 if order.length > 2 && order[2] =~ /^\d+$/
  684. 5 message = "大罪の上位存在 > #{subtotal}[#{natural_result.join(',')}]"
  685. 5 sin_weight = order[2].to_i
  686. 5 sin_count = 0
  687. 5 body: 9 while sin_count < 3 && total < sin_weight
  688. 9 modified_result = @randomizer.roll_barabara(3, 12)
  689. 9 total = results_multiplication(modified_result)
  690. 9 message += " > #{total}[#{modified_result.join(',')}]"
  691. 9 sin_count += 1
  692. end
  693. else: 1 else
  694. 1 message = "エラー:罪の重さを指定してください。"
  695. end
  696. 6 return message
  697. end
  698. 1 def fate_destruction(natural_result)
  699. 1 modified_result = natural_result.dup
  700. 1 modified_result << @randomizer.roll_once(12)
  701. 1 subtotal = results_multiplication(natural_result)
  702. 1 total = results_multiplication(modified_result) - 300
  703. 1 message = "破壊の上位存在 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  704. 1 return message
  705. end
  706. 1 def fate_anguish(natural_result)
  707. 2 modified_result = []
  708. 2 natural_result.each do |result|
  709. 6 then: 5 else: 1 if result < 7
  710. 5 result = 7
  711. end
  712. 6 modified_result << result
  713. end
  714. 2 subtotal = results_multiplication(natural_result)
  715. 2 total = results_multiplication(modified_result)
  716. 2 message = "懊悩の上位存在 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  717. 2 return message
  718. end
  719. 1 def fate_ordeal(natural_result)
  720. 2 modified_result = []
  721. 2 natural_result.each do |result|
  722. 6 then: 5 else: 1 if result < 9
  723. 5 result = 9
  724. end
  725. 6 modified_result << result
  726. end
  727. 2 subtotal = results_multiplication(natural_result)
  728. 2 total = results_multiplication(modified_result)
  729. 2 message = "試練の上位存在 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  730. 2 return message
  731. end
  732. 1 def fate_creation(natural_result)
  733. 3 modified_result = natural_result.dup
  734. 3 temporary_result = natural_result.dup
  735. 3 temporary_result.sort!
  736. 3 modified_result << temporary_result[1]
  737. 3 subtotal = results_multiplication(natural_result)
  738. 3 total = results_multiplication(modified_result)
  739. 3 message = "創造の上位存在 > #{subtotal}[#{natural_result.join(',')}] > #{total}[#{modified_result.join(',')}]"
  740. 3 return message
  741. end
  742. 1 def fate_element()
  743. 1 modified_result = []
  744. 1 modified_result << @randomizer.roll_once(4)
  745. 1 modified_result << @randomizer.roll_once(6)
  746. 1 modified_result << @randomizer.roll_once(8)
  747. 1 modified_result << @randomizer.roll_once(12)
  748. 1 modified_result << @randomizer.roll_once(20)
  749. 1 total = results_multiplication(modified_result)
  750. 1 message = "元素の上位存在 > #{total}[#{modified_result.join(',')}]"
  751. 1 return message
  752. end
  753. # 汎用
  754. 1 def results_multiplication(result_list)
  755. 135 total = 1
  756. 135 result_list.each do |result|
  757. 483 total *= result
  758. end
  759. 135 return total
  760. end
  761. 1 def stranger_effection(result_list)
  762. 11 stranger_list = []
  763. 11 result_list.each do |result|
  764. 33 stranger_list << result - 1
  765. end
  766. 11 return stranger_list
  767. end
  768. 1 def result_raoundup(result)
  769. 3 then: 2 if result.even?
  770. 2 return result / 2
  771. else: 1 else
  772. 1 return result / 2 + 1
  773. end
  774. end
  775. end
  776. end
  777. end

lib/bcdice/game_system/Hieizan.rb

100.0% lines covered

92.86% branches covered

21 relevant lines. 21 lines covered and 0 lines missed.
14 total branches, 13 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Hieizan < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Hieizan'
  7. # ゲームシステム名
  8. 1 NAME = '比叡山炎上'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ひえいさんえんしよう'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = "大成功、自動成功、失敗、自動失敗、大失敗の自動判定を行います。\n"
  13. # ゲーム別成功度判定(1d100)
  14. 1 def result_1d100(total, _dice_total, cmp_op, target)
  15. 14 then: 1 else: 13 return Result.nothing if target == '?'
  16. 13 else: 13 then: 0 return nil unless cmp_op == :<=
  17. 13 then: 2 if total >= 100
  18. 2 else: 11 Result.fumble("大失敗")
  19. 11 then: 3 elsif total >= 96
  20. 3 else: 8 Result.failure("自動失敗")
  21. 8 then: 2 elsif total <= (target / 5)
  22. 2 else: 6 Result.critical("大成功")
  23. 6 then: 1 elsif total <= 1
  24. 1 else: 5 Result.success("自動成功")
  25. 5 then: 4 elsif total <= target
  26. 4 Result.success("成功")
  27. else: 1 else
  28. 1 Result.failure("失敗")
  29. end
  30. end
  31. end
  32. end
  33. end

lib/bcdice/game_system/HouraiGakuen.rb

98.33% lines covered

86.84% branches covered

120 relevant lines. 118 lines covered and 2 lines missed.
38 total branches, 33 branches covered and 5 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class HouraiGakuen < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'HouraiGakuen'
  7. # ゲームシステム名
  8. 1 NAME = '蓬莱学園の冒険!!'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ほうらいかくえんのほうけん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・基本ロール:ROL(x+n)
  14. ROLL(自分の能力値 + 簡単値 + 応石 or 蓬莱パワー)と記述します。3D6をロールし、成功したかどうかを表示します。
  15. 例)ROL(4+6)
  16. ・対人判定:MED(x,y)
  17. 自分の能力値 x と 相手の能力値 y でロールを行い、成功したかどうかを表示します。
  18. 例)MED(5,2)
  19. ・対抗判定:RES(x,y)
  20. 自分の能力値 x と 相手の能力値 y で相互にロールし、どちらが成功したかを表示します。両者とも成功 or 失敗の場合は引き分けとなります。
  21. 例)RES(6,4)
  22. ・陰陽コマンド INY
  23. 例)Hourai : 陽(奇数の方が多い)
  24. ・五行コマンド:GOG
  25. 例)Hourai : 五行表(3) → 五行【土】
  26. ・八徳コマンド:HTK
  27. 例)Hourai : 仁義八徳は、【義】(奇数、奇数、偶数)
  28. INFO_MESSAGE_TEXT
  29. 1 register_prefix('ROL', 'MED', 'RES', 'INY', 'HTK', 'GOG')
  30. # ゲームの名前
  31. # チャット欄表示名
  32. # 判定用前置文字
  33. # 説明文
  34. # コマンド分岐
  35. 1 def eval_game_system_specific_command(command)
  36. 47 else: 0 case command
  37. when: 9 when /^ROL/i
  38. 9 return getRollResult(command)
  39. when: 9 when /^MED/i
  40. 9 return getMedResult(command)
  41. when: 11 when /^RES/i
  42. 11 return getResResult(command)
  43. when: 4 when /^INY/i
  44. 4 return getInnyouResult(command)
  45. when: 8 when /^HTK/i
  46. 8 return getHattokuResult(command)
  47. when: 6 when /^GOG$/i
  48. 6 return getGogyouResult(command)
  49. end
  50. return nil
  51. end
  52. 1 CRITICAL = "大成功"
  53. 1 SUCCESS = "成功"
  54. 1 FAILURE = "失敗"
  55. 1 FUMBLE = "大失敗"
  56. # 基本ロール
  57. 1 def getRollResult(command)
  58. 9 else: 9 then: 0 return nil unless /rol([-\d]+)/i =~ command
  59. # 目標値セット
  60. 9 target = Regexp.last_match(1).to_i
  61. 9 dice_list = @randomizer.roll_barabara(3, 6)
  62. 9 total = dice_list.sum()
  63. 9 diceText = dice_list.join(",")
  64. 9 result = getCheckResult(dice_list, total, target)
  65. 9 return "(3d6<=#{target}) > 出目#{diceText}=合計#{total} > #{result}"
  66. end
  67. 1 def getCheckResult(diceList, total, target)
  68. 40 diceList = diceList.sort
  69. 40 then: 3 else: 37 if isFamble(diceList)
  70. 3 return FUMBLE
  71. end
  72. 37 then: 18 else: 19 if isCritical(diceList)
  73. 18 return CRITICAL
  74. end
  75. 19 then: 13 else: 6 if total <= target
  76. 13 return SUCCESS
  77. end
  78. 6 return FAILURE
  79. end
  80. 1 def isFamble(diceList)
  81. 40 return diceList == [6, 6, 6]
  82. end
  83. 1 def isCritical(diceList)
  84. 37 return diceList == [1, 2, 3]
  85. end
  86. # 対人ロール
  87. 1 def getMedResult(command)
  88. 9 else: 9 then: 0 return nil unless /med\((\d+),(\d+)\)/i =~ command
  89. 9 yourValue = Regexp.last_match(1).to_i # あなたの値
  90. 9 enemyValue = Regexp.last_match(2).to_i # 相手の値
  91. 9 target = getTargetFromValue(yourValue, enemyValue) # 値から目標値を作出
  92. 9 dice_list = @randomizer.roll_barabara(3, 6)
  93. 9 total = dice_list.sum()
  94. 9 diceText = dice_list.join(",")
  95. 9 result = getCheckResult(dice_list, total, target)
  96. 9 return "(あなたの値#{yourValue}、相手の値#{enemyValue}、3d6<=#{target}) > 出目#{diceText}=合計#{total} > #{result}"
  97. end
  98. 1 def getTargetFromValue(yourValue, enemyValue)
  99. 31 yourValue + (10 - enemyValue) # 値から目標値を作出
  100. end
  101. # 対抗ロール
  102. 1 def getResResult(command)
  103. 11 else: 11 then: 0 return nil unless /res\((\d+),(\d+)\)/i =~ command
  104. 11 yourValue = Regexp.last_match(1).to_i # あなたの値
  105. 11 enemyValue = Regexp.last_match(2).to_i # 相手の値
  106. # 値から目標値を作出
  107. 11 yourTarget = getTargetFromValue(yourValue, enemyValue)
  108. 11 enemyTarget = getTargetFromValue(enemyValue, yourValue)
  109. 11 your_dice_list = @randomizer.roll_barabara(3, 6)
  110. 11 yourTotal = your_dice_list.sum()
  111. 11 yourDiceText = your_dice_list.join(",")
  112. 11 enemy_dice_list = @randomizer.roll_barabara(3, 6)
  113. 11 enemyTotal = enemy_dice_list.sum()
  114. 11 enemyDiceText = enemy_dice_list.join(",")
  115. 11 yourResult = getCheckResult(your_dice_list, yourTotal, yourTarget)
  116. 11 enemyResult = getCheckResult(enemy_dice_list, enemyTotal, enemyTarget)
  117. 11 result = getResistCheckResult(yourResult, enemyResult)
  118. 11 return "あなたの値#{yourValue}、相手の値#{enemyValue}
  119. (あなたのロール 3d6<=#{yourTarget}) > #{yourDiceText}=#{yourTotal} > #{yourResult}
  120. (相手のロール 3d6<=#{enemyTarget}) > #{enemyDiceText}=#{enemyTotal} > #{enemyResult}
  121. >#{result}"
  122. end
  123. 1 def getResistCheckResult(yourResult, enemyResult)
  124. 11 yourRank = getResultRank(yourResult)
  125. 11 enemyRank = getResultRank(enemyResult)
  126. 11 then: 7 else: 4 if yourRank > enemyRank
  127. 7 return "あなたが勝利"
  128. end
  129. 4 then: 2 else: 2 if yourRank < enemyRank
  130. 2 return "相手が勝利"
  131. end
  132. 2 return "引き分け"
  133. end
  134. 1 def getResultRank(result)
  135. ranks = [
  136. 22 FUMBLE,
  137. FAILURE,
  138. SUCCESS,
  139. CRITICAL,
  140. ]
  141. 22 return ranks.index(result)
  142. end
  143. # 陰陽コマンド
  144. 1 def getInnyouResult(_command)
  145. 4 oddCount = 0
  146. 4 evenCount = 0
  147. 4 3.times do
  148. 12 dice = @randomizer.roll_once(6)
  149. 12 then: 6 if dice.even?
  150. 6 evenCount += 1 # 偶数カウント
  151. else: 6 else
  152. 6 oddCount += 1 # 奇数カウント
  153. end
  154. end
  155. 4 then: 2 if evenCount < oddCount
  156. 2 return "陽(奇数の方が多い)"
  157. else: 2 else
  158. 2 return "陰(偶数の方が多い)"
  159. end
  160. end
  161. # 八徳コマンド
  162. 1 def getHattokuResult(_command)
  163. # 3回振って、奇数・偶数がどの順序で出たかを記録する
  164. 8 oddEvenList = []
  165. 8 3.times do
  166. 24 oddEvenList << getOddEven
  167. end
  168. 8 oddEvenText = oddEvenList.join("、")
  169. 8 case oddEvenText
  170. when: 1 when "奇数、奇数、奇数"
  171. 1 return "仁義八徳は、【仁】(#{oddEvenText})"
  172. when: 1 when "奇数、奇数、偶数"
  173. 1 return "仁義八徳は、【義】(#{oddEvenText})"
  174. when: 1 when "奇数、偶数、奇数"
  175. 1 return "仁義八徳は、【礼】(#{oddEvenText})"
  176. when: 1 when "奇数、偶数、偶数"
  177. 1 return "仁義八徳は、【智】(#{oddEvenText})"
  178. when: 1 when "偶数、奇数、奇数"
  179. 1 return "仁義八徳は、【忠】(#{oddEvenText})"
  180. when: 1 when "偶数、奇数、偶数"
  181. 1 return "仁義八徳は、【信】(#{oddEvenText})"
  182. when: 1 when "偶数、偶数、奇数"
  183. 1 return "仁義八徳は、【孝】(#{oddEvenText})"
  184. when: 1 when "偶数、偶数、偶数"
  185. 1 return "仁義八徳は、【悌】(#{oddEvenText})"
  186. else: 0 else
  187. return "異常終了"
  188. end
  189. end
  190. 1 def getOddEven
  191. 24 dice = @randomizer.roll_once(6)
  192. 24 then: 12 else: 12 return "偶数" if dice.even?
  193. 12 return "奇数"
  194. end
  195. 1 def getGogyouResult(_command)
  196. 6 type = '五行表'
  197. 6 table = getGogyouTable
  198. 6 text, number = get_table_by_1d6(table)
  199. 6 output = "#{type}(#{number}) > #{text}"
  200. 6 return output
  201. end
  202. # 五行コマンド
  203. 1 def getGogyouTable
  204. 6 table = [
  205. '五行【木】',
  206. '五行【火】',
  207. '五行【土】',
  208. '五行【金】',
  209. '五行【水】',
  210. '五行は【任意選択】',
  211. ]
  212. 6 return table
  213. end
  214. end
  215. end
  216. end

lib/bcdice/game_system/HunterTheReckoning5th.rb

98.67% lines covered

97.06% branches covered

75 relevant lines. 74 lines covered and 1 lines missed.
34 total branches, 33 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class HunterTheReckoning5th < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'HunterTheReckoning5th'
  7. # ゲームシステム名
  8. 1 NAME = 'Hunter: The Reckoning 5th Edition'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'はんあたされこにんく5'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定コマンド(nHRFx+x)
  14. 注意:難易度は必要成功数を表す
  15. 難易度指定:成功数のカウント、判定成功と失敗、Critical処理、Critical Win、Total Failureのチェックを行う
  16. (Desperationダイスがある場合)OverreachとDespairの発生チェックを行う
  17. 例) (難易度)HRF(通常ダイス)+(Desperationダイス)
  18. (難易度)HRF(通常ダイス)
  19. 難易度省略:成功数のカウント、判定失敗、Critical処理、Total Failure、(Desperationダイスがある場合)Despairチェックを行う
  20. 判定成功、Overreachのチェックを行わない
  21. Critical Win、(Desperationダイスがある場合)Despair、Overreachのヒントを出力
  22. 例) HRF(通常ダイス)+(Desperationダイス)
  23. HRF(通常ダイス)
  24. 難易度0指定:全てのチェックを行わない
  25. 例) 0HRF(通常ダイス)+(Desperationダイス)
  26. 0HRF(通常ダイス)
  27. MESSAGETEXT
  28. 1 DIFFICULTY_INDEX = 1
  29. 1 DICE_POOL_INDEX = 3
  30. 1 DESPERATION_DICE_INDEX = 5
  31. # 難易度に指定可能な特殊値
  32. 1 NOT_CHECK_SUCCESS = -1 # 判定成功にかかわるチェックを行わない(判定失敗に関わるチェックは行う)
  33. # ダイスボットで使用するコマンドを配列で列挙する
  34. 1 register_prefix('\d*HRF')
  35. 1 def eval_game_system_specific_command(command)
  36. 64 m = /\A(\d+)?(HRF)(\d+)(\+(\d+))?$/.match(command)
  37. 64 else: 64 then: 0 unless m
  38. return ''
  39. end
  40. 64 dice_pool = m[DICE_POOL_INDEX].to_i
  41. 64 dice_text, success_dice, ten_dice, = make_dice_roll(dice_pool)
  42. 64 result_text = "(#{dice_pool}D10"
  43. 64 then: 44 else: 20 desperaton_dice_pool = m[DESPERATION_DICE_INDEX]&.to_i
  44. 64 then: 44 if desperaton_dice_pool
  45. 44 then: 1 else: 43 if desperaton_dice_pool > 5
  46. 1 return "Desperationダイス指定は5ダイスが最大です。"
  47. end
  48. 43 desperaton_dice_text, desperaton_success_dice, desperaton_ten_dice, desperaton_botch_dice = make_dice_roll(desperaton_dice_pool)
  49. 43 ten_dice += desperaton_ten_dice
  50. 43 success_dice += desperaton_success_dice
  51. 43 result_text = "#{result_text}+#{desperaton_dice_pool}D10) > [#{dice_text}]+[#{desperaton_dice_text}] "
  52. else: 20 else
  53. 20 desperaton_ten_dice = 0
  54. 20 desperaton_botch_dice = 0
  55. 20 result_text = "#{result_text}) > [#{dice_text}] "
  56. end
  57. 63 success_dice += get_critical_success(ten_dice)
  58. 63 then: 41 else: 22 difficulty = m[DIFFICULTY_INDEX] ? m[DIFFICULTY_INDEX].to_i : NOT_CHECK_SUCCESS
  59. 63 return get_roll_result(result_text, success_dice, ten_dice, desperaton_ten_dice, desperaton_botch_dice, difficulty)
  60. end
  61. 1 private
  62. 1 def get_roll_result(result_text, success_dice, ten_dice, _desperaton_ten_dice, desperaton_botch_dice, difficulty)
  63. 63 result_text = "#{result_text} 成功数=#{success_dice}"
  64. 63 is_critical = ten_dice >= 2
  65. 63 desperation_result = ""
  66. 63 then: 27 if difficulty > 0
  67. 27 result_text = "#{result_text} 難易度=#{difficulty}"
  68. 27 then: 19 if success_dice >= difficulty
  69. 19 result_text = "#{result_text} 差分=#{success_dice - difficulty}"
  70. 19 then: 6 else: 13 if desperaton_botch_dice > 0
  71. 6 desperation_result = " [Overreach or Despair?]"
  72. end
  73. 19 then: 12 if is_critical
  74. 12 return Result.critical("#{result_text}:判定成功! [Critical Win]#{desperation_result}")
  75. else: 7 else
  76. 7 return Result.success("#{result_text}:判定成功!#{desperation_result}")
  77. end
  78. else: 8 else
  79. 8 then: 2 else: 6 if desperaton_botch_dice > 0
  80. 2 return Result.fumble("#{result_text}:判定失敗! [Despair]")
  81. end
  82. 6 then: 2 else: 4 if success_dice == 0
  83. 2 return Result.fumble("#{result_text}:判定失敗! [Total Failure]")
  84. end
  85. 4 return Result.failure("#{result_text}:判定失敗!")
  86. else: 36 end
  87. 36 then: 22 else: 14 elsif difficulty < 0
  88. 22 then: 6 if success_dice == 0
  89. 6 then: 2 else: 4 if desperaton_botch_dice > 0
  90. 2 return Result.fumble("#{result_text}:判定失敗! [Despair]")
  91. end
  92. 4 return Result.fumble("#{result_text}:判定失敗! [Total Failure]")
  93. else: 16 else
  94. 16 then: 6 else: 10 if desperaton_botch_dice > 0
  95. 6 result_text = "#{result_text}\n 判定失敗なら [Despair]"
  96. 6 desperation_result = " [Overreach or Despair?]"
  97. end
  98. 16 then: 8 if is_critical
  99. 8 else: 8 result_text = "#{result_text}\n 判定成功なら [Critical Win]"
  100. 8 then: 2 else: 6 elsif desperaton_botch_dice > 0
  101. 2 result_text = "#{result_text}\n 判定成功なら"
  102. end
  103. 16 return "#{result_text}#{desperation_result}"
  104. end
  105. end
  106. # 難易度0指定(=全ての判定チェックを行わない)
  107. 14 return result_text.to_s
  108. end
  109. 1 def get_critical_success(ten_dice)
  110. # 10の目が2個毎に追加2成功
  111. 63 return ((ten_dice / 2) * 2)
  112. end
  113. 1 def make_dice_roll(dice_pool)
  114. 107 dice_list = @randomizer.roll_barabara(dice_pool, 10)
  115. 107 dice_text = dice_list.join(',')
  116. 401 success_dice = dice_list.count { |x| x >= 6 }
  117. 107 ten_dice = dice_list.count(10)
  118. 107 botch_dice = dice_list.count(1)
  119. 107 return dice_text, success_dice, ten_dice, botch_dice
  120. end
  121. end
  122. end
  123. end

lib/bcdice/game_system/HuntersMoon.rb

98.39% lines covered

88.89% branches covered

62 relevant lines. 61 lines covered and 1 lines missed.
18 total branches, 16 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class HuntersMoon < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'HuntersMoon'
  7. # ゲームシステム名
  8. 1 NAME = 'ハンターズ・ムーン'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'はんたあすむうん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定
  14.  判定時にクリティカルとファンブルを自動判定します。
  15. ・各種表
  16.  ・遭遇表 (ET)
  17.  ・都市ロケーション表 (CLT)
  18.  ・閉所ロケーション表 (SLT)
  19.  ・炎熱ロケーション表 (HLT)
  20.  ・冷暗ロケーション表 (FLT)
  21.  ・部位ダメージ決定表 (DLT)
  22.  ・モノビースト行動表 (MAT)
  23.  ・異形アビリティー表 (SATx) (xは個数)
  24.  ・異形アビリティー表2 (SA2Tx) (xは個数)
  25.   →表1と表2の振り分けも判定
  26.  ・指定特技表 RTTn(n=分野番号、省略可能)
  27. 1.社会(TST) 2.頭部(THT) 3.腕部(TAT) 4.胴部(TBT) 5.脚部(TLT) 6.環境(TET)
  28.  ・異形化表      (MST)
  29.  ・代償表       (ERT)
  30.  ・ディフェンス遭遇表1/2/3 (DS1ET/DS2ET/DS3ET)
  31.  ・エスケープ遭遇表1/2/3 (EE1ET/EE2ET/EE3ET)
  32.  ・エスコート遭遇表1/2/3 (ET1ET/ET2ET/ET3ET)
  33.  ・トラッキング遭遇表1/2/3 (TK1ET/TK2ET/TK3ET)
  34. ・D66ダイスあり
  35. INFO_MESSAGE_TEXT
  36. 1 def initialize(command)
  37. 175 super(command)
  38. 175 @sort_add_dice = true
  39. 175 @d66_sort_type = D66SortType::ASC
  40. 175 @round_type = RoundType::CEIL # 端数切り上げに設定
  41. end
  42. # ゲーム別成功度判定(2D6)
  43. 1 def result_2d6(_total, dice_total, _dice_list, cmp_op, _target)
  44. 7 else: 7 then: 0 return nil unless cmp_op == :>=
  45. 7 then: 2 if dice_total <= 2
  46. 2 else: 5 Result.fumble("ファンブル(モノビースト追加行動+1)")
  47. 5 then: 2 else: 3 elsif dice_total >= 12
  48. 2 Result.critical("スペシャル(変調1つ回復orダメージ+1D6)")
  49. end
  50. end
  51. 1 def eval_game_system_specific_command(command)
  52. 168 case command
  53. when: 36 when /^SA/i
  54. 36 roll_strange_ability_table(command)
  55. else: 132 else
  56. 132 roll_tables(command, TABLES) || RTT.roll_command(randomizer, command)
  57. end
  58. end
  59. 1 def roll_strange_ability_table(command)
  60. 36 m = /^SA(2)?T(\d+)?$/.match(command)
  61. 36 else: 36 then: 0 unless m
  62. return nil
  63. end
  64. 36 then: 21 else: 15 count = m[2]&.to_i || 1
  65. 36 type2 = !m[1].nil?
  66. 36 then: 6 else: 30 table = type2 ? StrangeAbilityTable2.new : StrangeAbilityTable1.new
  67. 36 dice_list = []
  68. 36 chosen_list = []
  69. 36 count.times do
  70. 148 table.roll(@randomizer)
  71. 148 dice_list << table.dice
  72. 148 chosen_list << table.chosen
  73. end
  74. 36 dice = dice_list.join(",")
  75. 36 chosen = chosen_list.join("/")
  76. 36 return "異形アビリティー表(#{dice}) > #{chosen}"
  77. end
  78. 1 class StrangeAbilityTable1
  79. 1 BODY = ['大牙', '大鎌', '針山', '大鋏', '吸血根', '巨大化', '瘴気', '火炎放射', '鑢', 'ドリル', '絶叫', '粘液噴射', '潤滑液', '皮膚装甲', '器官生成', '翼', '四肢複製', '分解', '異言', '閃光', '冷気', '悪臭', '化膿歯', '気嚢', '触手', '肉瘤', '暗視', '邪視', '超振動', '酸分泌', '結晶化', '裏腹', '融合', '嘔吐', '腐敗', '変色'].freeze
  80. 1 attr_reader :dice, :chosen
  81. 1 def roll(randomizer)
  82. 140 dice1 = randomizer.roll_once(6)
  83. 140 dice2 = randomizer.roll_once(6)
  84. 140 index = (dice1 - 1) * 6 + (dice2 - 1)
  85. 140 @dice = dice1 * 10 + dice2
  86. 140 @chosen = BODY[index]
  87. end
  88. end
  89. 1 class StrangeAbilityTable2
  90. 1 BODY = ['電撃', '障壁', '追加肢', '破裂球', '死病', 'ソナー', '未来視', '寄生体', '再構築', '分身', '大角', '鉄塊', '硬質化', '生命力吸収', '鬼火', '金縛り', '排出口', '金属化', '鋼鱗', '神経接合', '光翼', '環境適応', '消化剤', 'プロペラ', '血栓', '骨槍', '回転', '怒髪', '煙幕', '脂肪層', '逆棘', '偽頭', '赤化', '発条', '凶運', '巨砲'].freeze
  91. 1 attr_reader :dice, :chosen
  92. 1 def roll(randomizer)
  93. 8 dice = randomizer.roll_once(6)
  94. 8 then: 3 else: 5 table = dice.odd? ? StrangeAbilityTable1::BODY : BODY
  95. 8 then: 3 else: 5 table_id = dice.odd? ? 1 : 2
  96. 8 dice1 = randomizer.roll_once(6)
  97. 8 dice2 = randomizer.roll_once(6)
  98. 8 index = (dice1 - 1) * 6 + (dice2 - 1)
  99. 8 @dice = [dice, dice1 * 10 + dice2].join("-")
  100. 8 @chosen = "[表#{table_id}]#{table[index]}"
  101. end
  102. end
  103. 1 RTT = DiceTable::SaiFicSkillTable.new(
  104. [
  105. ['社会', ['怯える', '考えない', '話す', '黙る', '売る', '伝える', '作る', '憶える', '脅す', '騙す', '怒る']],
  106. ['頭部', ['聴く', '感覚器', '見つける', '反応', '閃く', '脳', '考える', '予感', '叫ぶ', '口', '噛む']],
  107. ['腕部', ['操作', '殴る', '斬る', '利き腕', '撃つ', '掴む', '投げる', '逆腕', '刺す', '振る', '締める']],
  108. ['胴部', ['塞ぐ', '呼吸器', '止める', '動かない', '受ける', '心臓', '逸らす', 'かわす', '落ちる', '消化器', '耐える',]],
  109. ['脚部', ['迫る', '走る', '蹴る', '利き脚', '跳ぶ', '仕掛ける', 'しゃがむ', '逆脚', '滑る', '踏む', '歩く']],
  110. ['環境', ['耐熱', '休む', '待つ', '捕らえる', '隠れる', '追う', 'バランス', '現れる', '追い込む', '休まない', '耐寒']]
  111. ],
  112. rttn: ['TST', 'THT', 'TAT', 'TBT', 'TLT', 'TET'],
  113. rttn_format: "指定特技(%<category_name>s)表(%<row_dice>d) > %<skill_name>s"
  114. )
  115. TABLES = {
  116. 1 "CLT" => DiceTable::Table.new(
  117. "都市ロケーション表",
  118. "1D6",
  119. [
  120. '住宅街/閑静な住宅街。不意打ちに適しているため、ハンターの攻撃判定に+1の修正をつけてもよい。',
  121. '学校/夜の学校。遮蔽物が多く入り組んだ構造のため、ハンターはブロック判定によって肩代わりしたダメージを1減少してもよい。',
  122. '駅/人のいない駅。全てのキャラクターがファンブル時に砂利に突っ込んだり伝染に接触しかけることで1D6のダメージを受ける。',
  123. '高速道路/高速道路の路上。全てのキャラクターが、ファンブル時には走ってきた車に跳ねられて1D6のダメージを受ける。',
  124. 'ビル屋上/高いビルの屋上。ハンターはファンブル時に屋上から落下して強制的に撤退する。命に別状はない',
  125. '繁華街/にぎやかな繁華街の裏路地。大量の人の気配が近くにあるため、モノビーストが撤退するラウンドが1ラウンド早くなる。決戦フェイズでは特に効果なし。',
  126. ]
  127. ),
  128. "SLT" => DiceTable::Table.new(
  129. "閉所ロケーション表",
  130. "1D6",
  131. [
  132. '地下倉庫/広々とした倉庫。探してみれば色々なものが転がっている。ハンターは戦闘開始時に好きなアイテムを一つ入手してもよい。',
  133. '地下鉄/地下鉄の線路上。全てのキャラクターが、ファンブル時にはなぜか走ってくる列車に撥ねられて1D6ダメージを受ける。',
  134. '地下道/暗いトンネル。車道や照明の落ちた地下街。ハンターは、ファンブル時にアイテムを一つランダムに失くしてしまう。',
  135. '廃病院/危険な廃物がたくさん落ちているため、誰もここで戦うのは好きではない。キャラクター全員の【モラル】を3点減少してから戦闘を開始する。',
  136. '下水道/人が2人並べるくらいの幅の下水道。メンテナンス用の明かりしかなく、非常に視界が悪いため、ハンターの攻撃判定に-1の修正がつく。',
  137. '都市の底/都市の全てのゴミが流れ着く場所。広い空洞にゴミが敷き詰められている。この敵対的な環境では、ハンターの攻撃判定に-1の修正がつく。さらにハンターは攻撃失敗時に2ダメージを受ける。',
  138. ]
  139. ),
  140. "HLT" => DiceTable::Table.new(
  141. "炎熱ロケーション表",
  142. "1D6",
  143. [
  144. '温室/植物が栽培されている熱く湿った場所。生命に満ち溢れた様子は、戦闘開始時にハンターの【モラル】を1点増加する。',
  145. '調理場/調理器具があちこちに放置された、アクションには多大なリスクをともなう場所。全てのキャラクターは、ファンブル時に良くない場所に手をついたり刃物のラックをひっくり返して1D6ダメージを受ける。',
  146. 'ボイラー室/モノビーストは蒸気機関の周囲を好む傾向があるが、ここはうるさくて気が散るうえに暑い。全てのキャラクターは、感情属性が「怒り」の場合、全てのアビリティの反動が1増加する。',
  147. '機関室/何らかの工場。入り組みすぎて周りを見通せないうえ、配置がわからず出たとこ勝負を強いられる。キャラクター全員が戦闘開始時に「妨害」の変調を発動する。',
  148. '火事場/事故現場なのかモノビーストの仕業か、あたりは激しく燃え盛っている。ハンターはファンブル時に「炎上」の変調を発動する。',
  149. '製鉄所/無人ながら稼働中の製鉄所。安全対策が不十分で、溶けた金属の周囲まで近づくことが可能だ。ハンターは毎ラウンド終了時に《耐熱》で行為判定をし、これに失敗すると「炎上」の変調を発動する。',
  150. ]
  151. ),
  152. "FLT" => DiceTable::Table.new(
  153. "冷暗ロケーション表",
  154. "1D6",
  155. [
  156. '冷凍保管室/食品が氷漬けにされている場所。ここではモノビーストは氷に覆われてしまう。モノビーストは戦闘開始時に「捕縛」の変調を発動する。',
  157. '墓地/死んだ人々が眠る場所。ここで激しいアクションを行うことは冒涜的だ。全てのキャラクターは感情属性が恐怖の場合、全てのアビリティの反動が1増加する。',
  158. '魚市場/発泡スチロールの箱に鮮魚と氷が詰まり、コンクリートの床は濡れていて滑りやすい。ハンターはファンブル時に転んで1D6ダメージを受ける。',
  159. '博物館/すっかり静まり返った博物館で、モノビーストは動物の剥製の間に潜んでいる。紛らわしい展示物だらけであるため、ハンターは攻撃判定に-1の修正を受ける。',
  160. '空き地/寒風吹きすさぶ空き地。長くいると凍えてしまいそうだ。ハンターはファンブル時に身体がかじかみ、「重傷」の変調を発動する。',
  161. '氷室/氷で満たされた洞窟。こんな場所が都市にあったとは信じがたいが、とにかくひどく寒い。ハンターは毎ラウンド終了時に《耐寒》で判定し、失敗すると「重傷」の変調を発動する。',
  162. ]
  163. ),
  164. "ET" => DiceTable::Table.new(
  165. "遭遇表",
  166. "1D6",
  167. [
  168. '獲物/恐怖/あなたはモノビーストの獲物として追い回される。満月の夜でないと傷を負わせることができない怪物相手に、あなたは逃げ回るしかない。',
  169. '暗闇/恐怖/あの獣は暗闇の中から現れ、暗闇の中へ消えていった。どんなに振り払おうとしても、あの恐ろしい姿の記憶から逃れられない。',
  170. '依頼/怒り/あなたはモノビーストの被害者の関係者、あるいはハンターや魔術師の組織から、モノビーストを倒す依頼を受けた。',
  171. '気配/恐怖/街の気配がどこかおかしい。視線を感じたり、物音が聞こえたり・・・だが、獣の姿を捉えることはできない。漠然とした恐怖があなたの心をむしばむ。',
  172. '現場/怒り/あなたはモノビーストが獲物を捕食した現場を発見した。派手な血の跡が目に焼きつく。こんなことをする奴を生かしてはおけない。',
  173. '賭博/怒り/あなたの今回の獲物は、最近ハンターの間で話題になっているモノビーストだ。次の満月の夜にあいつを倒せるか、あなたは他のハンターと賭けをした。',
  174. ]
  175. ),
  176. "MAT" => DiceTable::Table.new(
  177. "モノビースト行動表",
  178. "1D6",
  179. [
  180. '社会/モノビーストは時間をかけて逃げ続けることで、ダメージを回復しようとしているようだ。部位ダメージを自由に一つ回復する。部位ダメージを受けていない場合、【モラル】が1D6回復する。',
  181. '頭部/モノビーストはハンターを撒こうとしている。次の戦闘が日暮れ、もしくは真夜中である場合、モノビーストは1ラウンド少ないラウンドで撤退する。次の戦闘が夜明けである場合、【モラル】が2D6増加する。',
  182. '腕部/モノビーストは若い犠牲者を選んで捕食しようとしている。どうやら力を増そうとしているらしい。セッション終了までモノビーストの攻撃によるダメージは+1の修正がつく。',
  183. '胴部/モノビーストは別のハンターと遭遇し、それを食べて新しいアビリティを手に入れる! ランダムに異形アビリティを一つ決定し、修得する。',
  184. '脚部/モノビーストはハンターを特定の場所に誘導しているようだ。ロケーション表を振り、次の戦闘のロケーションを変更する。そのロケーションで次の戦闘が始まった場合、モノビーストは最初のラウンドに追加行動を1回得る。',
  185. '環境/モノビーストは移動中に人間の団体と遭遇し、食い散らかす。たらふく食ったモノビーストは【モラル】を3D6点増加させる',
  186. ]
  187. ),
  188. "DLT" => DiceTable::Table.new(
  189. "部位ダメージ決定表",
  190. "2D6",
  191. [
  192. '脳',
  193. '利き腕',
  194. '利き脚',
  195. '消化器',
  196. '感覚器',
  197. '攻撃したキャラクターの任意の部分',
  198. '口',
  199. '呼吸器',
  200. '逆脚',
  201. '逆腕',
  202. '心臓',
  203. ]
  204. ),
  205. "DS1ET" => DiceTable::Table.new(
  206. "ディフェンス遭遇表1st",
  207. "1D6",
  208. [
  209. "状況 あなたはモノビーストに追い詰められるまま建物に閉じこもる。とりあえず、夜は建物の中を威勢よく動き回り、相手を威嚇しなければ。\n指定特技 《脅す/社会10》\n成功 建物の外から隙を窺うモノビーストをきつく睨みつける。感情属性を「怒り」に設定。\n失敗 ヤツはあなたを嘲笑うかのように建物の中に出現を繰り返す。感情属性を「恐怖」に設定。",
  210. "状況 廃墟となって久しいこの建物には、ハンターがいた形跡がある。山と仕掛けられれたトラップに気をつけながら探索を続けるが……。\n指定特技 《見つける/頭部4》\n成功 裏口で格闘の跡を見つける。何かの事情で、出たところを襲われたのだ。感情属性を「怒り」に設定。\n失敗 トラップに引っかかり怪我をする。こんなところに立て篭もって大丈夫か?感情属性を「恐怖」に設定。",
  211. "状況 あなたの友人のハンターは脚に重傷を負って動けない。しばらくこの建物の中で回復を待つしかなさそうだが、彼は足手まといになるのを嫌って戸外で死のうとする。止めよう。\n指定特技 《逆腕/腕部9》\n成功 必死に引き止めた戸口の向こうで、笑うような息遣いが聞こえた。感情属性を「恐怖」に設定。\n失敗 制止を振り切って出て行った友人は死んだ。感情属性を「怒り」に設定。",
  212. "状況 エレベーターが落ちた。不運な同行者と一緒に、誰も来ないビルの地下に閉じ込められる。落ちる寸前、天井で聞いた音は間違いなくヤツのものだ。\n指定特技 《落ちる/胴部10》\n成功 怪我もなく落下を切り抜けたが、同行者を連れて出て行く手段がない。感情属性を「恐怖」に設定。\n失敗 ショックでパニックに陥った同行者はあなたを責め立てる。感情属性を「怒り」に設定。",
  213. "状況 今回の相手は光が強い環境では消散能力を使えないようだ。あなたは建物中を駆けまわって、照明をつけてまわる。\n指定特技 《逆脚/脚部9》\n成功 なんとか防御体制は整ったが、送電線が気に掛かる。感情属性を「恐怖」に設定。\n失敗 間に合わない。建物の半分の送電が絶たれ、あなたは狭い部屋に閉じこもることになる。感情属性を「怒り」に設定。",
  214. "状況 金がないのか脚が遅いのか、あなたは逃げ回ることができない。唯一の選択肢は、あらかじめ作っておいた隠れ家に潜むことだ。\n指定特技 《隠れる/環境6》\n成功 とりあえず、うまく隠れることができたようだ。感情属性を「怒り」に設定。\n失敗 隠れ家の装備は、すでに破壊されていた。感情属性を「恐怖」に設定。"
  215. ]
  216. ),
  217. "DS2ET" => DiceTable::Table.new(
  218. "ディフェンス遭遇表2nd",
  219. "1D6",
  220. [
  221. "状況 建物の構造を把握し、憶えこむことで、満月の晩までの生存率は大きく向上するだろう。あなたは眠い目を擦りつつ、昼間も探索を続ける。\n指定特技 《覚える/社会9》\n成功 やつを迎え撃つ自信が湧いてきた。【モラル】が2点増加する。\n失敗 眠くて全然覚えられない。体力を消耗してしまう。「重傷」の変調を発動する。",
  222. "状況 夜が来るたびに退屈な見張りが始まる。代わり映えのしない景色を眺めていると、モノビーストの襲撃に対する反応速度を保つのは難しい。\n指定特技 《反応/頭部5》\n成功 襲われたが難なくやり過ごす。感情属性を任意に変更できる。\n失敗 後ろに実体化したモノビーストに気付くのが遅れ、痛い代償を払うことになった。アイテムを任意に1つ失う。",
  223. "状況 モノビーストが実体化するにはある程度のスペースが必要だ。あなたは部屋の中にワイアを張り巡らし、空間を細分することで攻撃を防ぐ。\n指定特技 《斬る/腕部4》\n成功 モノビーストはあなたを警戒するあまり動きが鈍り、「妨害」の変調を発動する。\n失敗 動きづらくなっただけで襲撃が無い……【モラル】が2点減少する。",
  224. "状況 建物の中にあるものを何でも積んでバリケードを作る。霧になる相手には効果が薄いかもしれないが。移動を制限できるぶん、ないよりマシだ。\n指定特技 《心臓/胴部7》\n成功 この場所は満月の夜にヤツを追い詰める場所としても使えるだろう。【ネット】を入手する。\n失敗 堂々と壁を破って侵入された……撃退はしたが、自らのあまりの愚かさに「動転」してしまう。",
  225. "状況 自作の罠を建物のあちこちに配置する。うまくいけば、ヤツを退散させる程度の役には立つだろう。\n指定特技 《仕掛ける/脚部7》\n成功 うとうとしていた夜更け、悲鳴とともに逃げ出すモノビーストの移動音で目を覚ます。【モラル】が2点増加する。\n失敗 まるで意に介さないモノビーストに追い回されトラウマを負う。このセッションが終了するまで妨害判定にマイナス2の修正がつく。",
  226. "状況 やばい。寒い。空調の故障か季節が悪いのか、モノビーストと勝負する前に凍死してしまいそうだ。\n指定特技 《耐寒/環境12》\n成功 あなたは苦難を耐え切り、自信を身につける。次の遭遇表の行為判定にプラス2の修正がつく。\n失敗 我慢できなくなってアイテムを燃やして暖を取る。ランダムにアイテムを1つ失う。"
  227. ]
  228. ),
  229. "DS3ET" => DiceTable::Table.new(
  230. "ディフェンス遭遇表3rd",
  231. "1D6",
  232. [
  233. "状況 時は来た。問題は立て篭もっていた建物から出て行くタイミングだが、囮を使うことでモノビーストを騙し、安全に出ていけるかもしれない。\n指定特技 《騙す/社会11》\n成功 相手の不意を打った!次に行う行為判定にプラス2の修正がつく。\n失敗 逆に騙され、日が沈みきっていない早い時間に飛び出してしまう。モノビーストは夕暮れの戦闘で変調を発動しない。",
  234. "状況 長い潜伏期間を過ごした建物を振り返り、その上に出ている満月を見つめる。この夜でケリがつく。そんな予感があなたの胸を満たす。\n指定特技 《予感/頭部9》\n成功 どんな形で決着がつくか、脳裏にイメージが浮かぶ。感情属性を任意に変更できる。\n失敗 不安があなたの心を締め付ける。【感情】が2点増加する。",
  235. "状況 さて満月の夜だ。幸い投擲武器が豊富な場所にいるわけで、外にいるモノビーストに、すこし先制攻撃をさせてもらおう。\n指定特技 《投げる/腕部8》\n成功 投げたものがばらばらと当たり、相手はいらついている。モノビーストの【感情】が2点増加する。\n失敗 物を投げるのが楽しくなってしまい、狩りに出遅れる。夕暮れの追跡フェイズで行う判定にマイナス2の修正がつく。",
  236. "状況 ついに相手と対等になる夜だ、と意気揚々と外に出たあなたを、上空からの不意打ちが襲う。もちろん、ヤツはあなたを待ち構えていたのだ。\n指定特技 《かわす/胴部9》\n成功 待ち伏せくらいは予想のうちだ。【モラル】が2点増加する。\n失敗 まともに食らったが、アイテムのおかげで命拾いする。持っていれば【医療キット】を失う。",
  237. "状況 狭い所に閉じこもりきりで、これまで走り出したくてうずうずしていた脚に気合を入れる。今夜はどこまでも走っていけそうだ。\n指定特技 《走る/脚部3》\n成功 いい感じに体が軽い。このセッションの間、ロケーション変更判定にプラス2の修正がつく。\n失敗 いきなり脚をくじく。せめて準備運動はするべきだったかもしれない。【モラル】が4点減少する。",
  238. "状況 こんなこともあろうかと、あなたは秘密の出口を作っておいたのだ。予想もしない場所から出てくるあなたに、ヤツは恐れおののくに違いない。\n指定特技 《現れる/環境9》\n成功 かなり効果的に敵の虚をついた。モノビーストは次に得る追加行動を1回失う。\n失敗 秘密の出口はすでに破壊されていた……とぼとぼと戻る。【感情】が4点増加する。"
  239. ]
  240. ),
  241. "EE1ET" => DiceTable::Table.new(
  242. "エスケープ遭遇表1st",
  243. "1D6",
  244. [
  245. "状況 あなたは見た。夜の街を闊歩し、気ままに人を食い散らかす怪物を。すぐ近くまで追っている危険を、大事な人に伝えなければならない。\n指定特技 《伝える/社会7》\n成功 最近疲れてるんじゃない?と返され絶望する。感情属性を「恐怖」に設定。\n失敗 病院に連れて行かれた。感情属性を「怒り」に設定。",
  246. "状況 夜道で角を曲がったら怪物がいた。しかもばっちり目が合った。不運を嘆く暇もなく、ヤツは襲い掛かってくる。速く逃げないと!\n指定特技 《反応/頭部5》\n成功 逃げられたが理不尽さに怒りがこみ上げる。感情属性を「怒り」に設定。\n失敗 頭を食いちぎられる寸前で危うくも逃げ出す。感情属性を「恐怖」に設定。",
  247. "状況 買い物帰り、夜道を並んで歩いていた友人の上半身がいきなり消えた。喰われたのだ。今すぐヤツに買い物袋を投げつけろ。\n指定特技 《投げる/腕部8》\n成功 無駄になった食材と友人のため、感情属性を「怒り」に設定。\n失敗 散らばった買い物に足をとられて転び、捕食シーンをまざまざと見せつけられる。感情属性を「恐怖」に設定。",
  248. "状況 音がする。床を踏みしめる音。固い何かが触れ合う音。吐く息、吸う息、唸り声、悲鳴。何も聞こえないふりをしなければ、これは本当にあることになってしまう。\n指定特技 《耐える/胴部12》\n成功 パニックを起こさずに冷静に検討した結果、逃げなければならないと結論が出る。 感情属性を「怒り」に設定。\n失敗 パニックに陥りやみくもに逃げ出す。感情属性を「恐怖」に設定。",
  249. "状況 この子を頼む、と叫んで幼児を放り投げたハンターは、目の前でモノビーストに食われて死んだ。ヤツは明らかにこの子を狙っているし、まずは受け止める必要がある。\n指定特技 《跳ぶ/脚部6》\n成功 うまくキャッチ!この子を抱えて武器を振り回すわけにはいかない、まずは逃げよう。感情属性を「怒り」に設定。\n失敗 落とした……かと思ったよ。いや危ない危ない。感情属性を「恐怖」に設定。",
  250. "状況 きつい一日だった。下を向いて歩いていたからだろう。すぐ横にモノビーストがいるのに気付かなかった。あまりに近すぎて動揺し、足がもつれる。\n指定特技 《バランス/環境8》\n成功 見えていることは気づかれていない……感情属性を「恐怖」に設定。\n失敗 モノビーストと接触し、一晩中追い回される。感情属性を「怒り」に設定。"
  251. ]
  252. ),
  253. "EE2ET" => DiceTable::Table.new(
  254. "エスケープ遭遇表2nd",
  255. "1D6",
  256. [
  257. "状況 モノビーストから逃げるあなたの目の前に、パトロール中の警察官が!夜中に必死な顔で走っている理由をひねり出せ。\n指定特技 《騙す/社会11》\n成功 うまく言い抜けた。【モラル】が1点増加する。\n失敗 質問されているうちにモノビーストが追いつき、警察官を食い殺す。感情属性が反転する。",
  258. "状況 あの夜以来、毎晩モノビーストに追い回されている。完全に目をつけられたようだ。この状況から抜け出すために、あなたは眠い目を擦りながら昼間も考え続ける。\n指定特技 《考える/頭部8》\n成功 ヤツの能力について整理できた。このセッション中、弱点調査判定にプラス1の修正がつく。\n失敗 眠くて何も考えられない。感情属性を「恐怖」に設定。",
  259. "状況 車で街から逃走しようとしたところ、ひどい渋滞に引っかかって夜になり、案の定襲撃があって車をひっくり返された。武器になりそうなのは発炎筒だけだ……。\n指定特技 《撃つ/腕部6》\n成功 なんとか撃退成功。駆けつけたJAFの人から【医療キット】を入手できる。\n失敗 まるで効かない。車に積んであった装備を諦め、街に逃げ戻る。【感情】が2点増加する。",
  260. "状況 密閉した部屋に閉じこもり、隙間がないこと、ヤツが諦めてくれることを神に祈る。どんな神であれ、心から祈れば答えがあるかもしれない。\n指定特技 《心臓/胴部7》\n成功 徴が現れた!【勝利のお守り】を入手できる。\n失敗 何も起こらない。【感情】が2点増加する。",
  261. "状況 モノビーストには縄張りがある。まっすぐ歩き続ければ、いつかその外に出られるはずだ。\n指定特技 《歩く/脚部12》\n成功 行く先々で橋は落ち、停電は発生し、公共交通機関は止まっている。感情属性が反転する。\n失敗 いつのまにか迷子になってしまっている。「動転」の変調を発動する。",
  262. "状況 モノビーストから逃げ続けるなか、ヤツと戦う人間を見かける。あの人を追いかけられれば、協力できるかもしれない。\n指定特技 《追う/環境7》\n成功 任意の他のハンターと出会う。【モラル】が3点増加する。\n失敗 ダメだ、見失ってしまった。【感情】が2点増加する。"
  263. ]
  264. ),
  265. "EE3ET" => DiceTable::Table.new(
  266. "エスケープ遭遇表3rd",
  267. "1D6",
  268. [
  269. "状況 考え付く限りのルートと手段を使って逃げ続けたあなたがたどりついた袋小路には、モノビーストが待っていた。もう何も考えず、必死に戦うしかないようだ。\n指定特技 《考えない/社会3》\n成功 思考停止成功!感情属性を好きに変更できる。\n失敗 別のハンターが倒してくれるかもしれないと考えて気後れする。夕暮れの戦闘フェイズでは自分が行う全ての攻撃判定にマイナス1の修正がつく。",
  270. "状況 いつまでも逃げ続けるわけにはいかない。体力的にも限界が近づいている。この状況を打開する方法を見つけなければならない。\n指定特技 《見つける/頭部4》\n成功 モノビーストを殺せば逃げなくてもよくなると発見。【モラル】が2点増加する。\n失敗 どうも戦うしかないようだ。感情属性が反転する。",
  271. "状況 逃げるあなたの巻き添えで、また人が殺される。こんなのはもうたくさんだ。逃げればそのうち何とかなるという考えを振り払わねばならない。\n指定特技 《振る/腕部11》\n成功 弱気な考えを振り切った。この決意にあたるものとして【興奮剤】を入手することができる。\n失敗 勝てる気がしない。【モラル】が2点減少する。",
  272. "状況 空を見上げれば満月が浮かんでいる。あなたの実力をもってすれば、今ならモノビーストと戦える。今こそ逃げるのを止めて戦う時なのだ。\n指定特技 《止める/胴部3》\n成功 【激情】を1点得る。ただしこのセッションで【感情】が30になっても【激情】を得られない。\n失敗 明らかに怯えた様子のあなたを見て、モノビーストの【モラル】が3点増加する。",
  273. "状況 走ってどこまでも逃げていく。順調にいけば振りきれただろうが、ぬかるみ、血、それに類する何かによってあなたの足は滑り、モノビーストに追いつかれてしまう。覚悟を決める時が来たようだ。\n指定特技 《滑る/脚部10》\n成功 速度を利用していい位置に。夕暮れの戦闘フェイズでは先制判定を振らず、成功にすることができる。\n失敗 滑り方がよくなかった。「妨害」の変調を発動する。",
  274. "状況 ハンターが集まり、モノビーストに戦いを挑んでいる。今なら難なく逃げ切れるはずだ……しかし、彼らを見捨てることなどできない。あなたは来た道を引き返していく。\n指定特技 《現れる/環境9》\n成功 突然現れた増援に、モノビーストの【モラル】が2点減少する。\n失敗 逃げる途中で落し物。ランダムにアイテムを1つ失う。"
  275. ]
  276. ),
  277. "ERT" => DiceTable::Table.new(
  278. "代償表",
  279. "1D6",
  280. [
  281. "評判の失墜\n 次のセッションで登場するハンターキラーの合計レベルが1上昇します。\nこの代償を持つハンターがセッションに複数参加している場合、効果の累積はしません。",
  282. "闇夜の饗宴\n 次のセッションに登場するモノビーストのランクが1上昇します。\nこの代償を持つハンターがセッションに複数参加してる場合、効果の累積はしません。",
  283. "特技の忘却\n 習得した特技の中から1つを任意に選び、使用不能にします。\n次にモノビーストを殺したタイミングで、この特技は使用可能になります。\nこの代償を複数回得ることで特技が0個になったハンターは、判定および生活が不可能になって死亡します。最終判定すらできません。",
  284. "能力の不調\n 習得している汎用または武器アビリティの中から1つを任意に選び、使用不能にします。\n次にモノビーストを殺したタイミングで、このアビリティは使用可能になります。\nこの代償を複数回得ることでアビリティを全て失ったハンターは、戦闘不能となり引退します。",
  285. "自信の喪失\n 【モラル】基準値が1減少します。この減少は、次にモノビーストを殺したタイミングで元に戻ります。\nこの代償を複数回得ることで【モラル】基準値がマイナスになったハンターは、気力を完全に失い引退します。",
  286. "引退の決意\n 異形アビリティを全て失います。この代償で失った異形アビリティを回復することはできません。\nこの代償を続けて2回得た段階でハンターはモノビーストとの接触を失い、視認できなくなります。つまり強制的に引退です。"
  287. ]
  288. ),
  289. "ET1ET" => DiceTable::Table.new(
  290. "エスコート遭遇表1st",
  291. "1D6",
  292. [
  293. "状況 追われる彼/彼女があなたの前に現れたのは満月の夜。獲物に集中しているモノビーストを攻撃するのは容易いことだったが……。\n指定特技 《怯える/社会2》\n成功 今戦えば彼/彼女は死ぬと思いとどまって一緒に逃げる。感情属性を「恐怖」に設定。\n失敗 モノビーストを倒しきれず、彼/彼女は一生残る傷を負う。感情属性を「怒り」に設定。",
  294. "状況 彼/彼女は、窓を破りながらあなたの家に飛び込んできた。モノビーストは見えているようだが、あなたの渋い顔は見えていないようだ。\n指定特技 《反応/頭部5》\n成功 とっさに反応し、モノビーストを攻撃して追い払う。感情属性を「怒り」に設定。\n失敗 あまりの唐突さに襲い来るモノビーストへの対応が遅れ、部屋を放棄して逃げることになる。感情属性を「恐怖」に設定。",
  295. "状況 夜、あなたの隣を歩いている彼/彼女が不意打ちを受ける。どうやら獲物として選ばれたようだが、腕を引いて助けることはできるだろうか?\n指定特技 《利き腕/腕部5》\n成功 紙一重で攻撃を避けさせることに成功。感情属性を「恐怖」に設定。\n失敗 かばう形になり手傷を負う。感情属性を「怒り」に設定。",
  296. "状況 彼/彼女はどう見てもハンターとしては無能だが、あるモノビーストを倒す必要があるのだという。助力を頼まれたあなたは……。\n指定特技 《止める/頭部4》\n成功 その場の勢いで代わりに戦うことになってしまった。感情属性を「恐怖」に設定。\n失敗 説得するが失敗。彼/彼女は一人で夜の街へ飛び出す。感情属性を「怒り」に設定。",
  297. "状況 彼/彼女は子供で、子供を餌として好む怪物に追われていて、助けてやれる人はあなたしかいない。安心させるために目の高さを合わせてみよう。\n指定特技 《しゃがむ/脚部8》\n成功 彼/彼女はよくあなたに懐き、それを狙うモノビーストへの感情属性は「怒り」になる。\n失敗 全然ダメ。護衛を放り出すわけにもいかないが先行き不安だ。感情属性を「恐怖」に設定。",
  298. "状況 あなたはモノビーストの標的となった彼/彼女を数カ月にわたって守り続けている。逃避行のなか、気が休まるのは日が高いうちだけだ。\n指定特技 《休む/環境3》\n成功 よく休み気力は充分だ。今度の満月の夜に、この逃避行を終わらせる。感情属性を「怒り」に設定。\n失敗 ちょっとした暗がりにヤツが潜んでいる気がしてならない。まるで休めず、感情属性を「恐怖」に設定。"
  299. ]
  300. ),
  301. "ET2ET" => DiceTable::Table.new(
  302. "エスコート遭遇表2nd",
  303. "1D6",
  304. [
  305. "状況 彼/彼女は怪物に狙われる日々に憔悴している。モノビーストは狙いを変えたとか、もう死んだとか、元気付けるようなことを言わなくては。\n指定特技 《騙す/社会11》\n成功 一時しのぎの嘘だが元気な笑顔が見られる。【勝利のお守り】として記憶に刻んでおいてもよい。\n失敗 あなたの下手な嘘は彼/彼女を「動転」させる。あなたも影響を受けて同じ変調を発動する。",
  306. "状況 彼/彼女は執拗に狙われる理由を知りたがっている。考えてみよう。もしかしたら、戦わずにすむかもしれない。\n指定特技 《考える/頭部8》\n成功 モノビーストは彼/彼女と似たタイプの人間を殺してきているようだ。このセッション中、習性調査判定にプラス1の修正がつく。\n失敗 全然分からない。【感情】が2点増加する。",
  307. "状況 彼/彼女はあなたの献身的な姿に罪悪感を覚え、人知れず姿を消し、モノビーストに殺されることであなたの苦労を終わらせようとする。\n指定特技 《掴む/腕部7》\n成功 間一髪のところで掴まえた。感情属性を反転させる。\n失敗 あなたの手は届かない。行方不明になった彼/彼女を探すことで疲労困憊したあなたは「妨害」の変調を発動する。",
  308. "状況 何日も二人で過ごすうち、あなたの彼/彼女の間には愛情のようなものが芽生え始める。この気持ちは果たして本物だろうか?\n指定特技 《落ちる/胴部10》\n成功 真実の愛を発見したあなたの【モラル】は6点上昇する。\n失敗 ハンターに愛はいらない。感情属性を任意に変更できる。",
  309. "状況 不意をうたれた。モノビーストの襲撃から逃れるためには、彼/彼女を抱えて跳ぶしかない\n指定特技 《跳ぶ/脚部6》\n成功 危ういジャンプだったが何とかなった。【モラル】が2点増加する。\n失敗 彼/彼女を放り出し怒られる。釈然とせず【感情】が2点増加する。",
  310. "状況 あなたは眠らない。彼/彼女をモノビーストの牙にかけるわけにはいかないのだ。しかし、これをいつまで続けることができるのか?\n指定特技 《休まない/環境11》\n成功 疲労が溜まっていく……あなたは「重傷」の変調を発動する。\n失敗 いつのまにか眠ってしまっていたあなたに毛布がかけられている。幸い襲撃はなかったようだ。【モラル】が2点増加する。"
  311. ]
  312. ),
  313. "ET3ET" => DiceTable::Table.new(
  314. "エスコート遭遇表3rd",
  315. "1D6",
  316. [
  317. "状況 もうすぐ満月が昇る。あなたと彼/彼女は、モノビーストを倒した後に何をするか話しあう。希望の持てる未来のヴィジョンを作れただろうか?\n指定特技 《作る/社会8》\n成功 待ち受ける未来に対して任意に感情属性を変更することができる。\n失敗 特にすることがないような……やけになって【感情】が2点増加する。",
  318. "状況 あと数日で満月だというのに、彼/彼女はモノビーストに重傷を負わされ、死ぬ。あなたは微かな声で囁かれる最後の言葉を聞き取ろうとする。\n指定特技 《聴く/頭部2》\n成功 【モラル】が6点増加する。\n失敗 意味のある言葉は何も聴きとれない。失意に沈んだあなたはランダムな頭部カテゴリの特技1つが使用不可能になる。",
  319. "状況 やっと分かった。彼/彼女が肌身離さず持っていたアイテムが狙われる原因だったのだ。あなたは彼/彼女に、そのアイテムをこちらに投げ渡すように頼む。\n指定特技 《投げる/腕部8》\n成功 うまく投げてもらう。【幸運のお守り】を入手できる。\n失敗 あなたはアイテムを取り落とし、微妙な空気がただよう。【感情】が2点増加する。",
  320. "状況 あなたは夜の街を、彼/彼女の手を引いて駆け抜ける。もう少しで安全な場所につく。そうすれば、あなただけが戻って戦うことができる。\n指定特技 《心臓/胴部7》\n成功 これで彼/彼女の身は安全だ。このセッション中、あなたの【モラル】基準値は1点増加する。\n失敗 息切れ、および時間切れ。狩りの時間だ。ただしあなたの【モラル】は3点減少している。",
  321. "状況 満月を見上げながら、二人でこれまで踏みしめてきた道を振り返る。背後にモノビーストがいることは分かっている。しかし、もはや二人とも恐れはない……だろうか?\n指定特技 《踏む/脚部11》\n成功 彼/彼女は狩りの間あなたについていき、一度だけ【医療キット】に相当する応援をしてくれる。\n失敗 いつのまにか彼/彼女が逃げ出していることに気付く。「動転」の変調を発動する。",
  322. "状況 逃避行がクライマックスに近づくにつれ、二人の間の緊張感は耐え難いほどに高まる。このままでは恋に落ちてしまいそうだが、どうしたものだろうか。\n指定特技 《耐熱/環境2》\n成功 胸の熱い気持ちを押さえ込む。感情属性を任意に変更できる。\n失敗 彼/彼女のために頑張ろう。このセッション中、練習判定にプラス1の修正がつく。"
  323. ]
  324. ),
  325. "MST" => DiceTable::Table.new(
  326. "異形化表",
  327. "1D6",
  328. [
  329. "【感情】が2増加する。",
  330. "【感情】が4増加する。",
  331. "【感情】が6増加する。",
  332. "【感情】が6増加する。部位ダメージを受ける。",
  333. "【感情】が6増加する。異形アビリティをランダムに1つ失う。\n異形アビリティが1つもなければ部位ダメージを受ける。",
  334. "【感情】が6増加する。部位ダメージを2回受ける。"
  335. ]
  336. ),
  337. "TK1ET" => DiceTable::Table.new(
  338. "トラッキング遭遇表1st",
  339. "1D6",
  340. [
  341. "状況 あなたは隠れ場所に潜みながらモノビーストが獲物…あなたの大切な誰かを貪るのを見ている。満月の夜は遠く、まだ奴を仕留める事は出来ない。\n指定特技 《黙る/社会5》\n成功 押さえ込んだ怒りが膨れ上がる。感情属性を「怒り」に設定。\n失敗 思わず声を上げてしまい、無敵のモノビーストに手酷い傷を負わされる。感情属性を「恐怖」に設定。",
  342. "状況 すばらしい味だった。前の満月の晩に捕り逃した奴の血は、まさに超常的な美味。あの味を空気の中にまで感じ取ることができるようだ。\n指定特技 《口/頭部11》 \n成功 神々しい味を完璧にイメージできた。感情属性を「恐怖」に設定。\n失敗 待ちきれなくて口の中を噛む。感情属性を「怒り」に設定。",
  343. "状況 夜、屋根の上。あなたはモノビーストが人家に忍び込まないよう牽制している。屋根はもともと走りまわるようにはできていないのだが。\n指定特技 《掴む/腕部7》\n成功 屋根の縁を掴んで落下を免れる。感情属性を「怒り」に設定。\n失敗 屋根から落ちてひどい目にあう。感情属性を「恐怖」に設定。",
  344. "状況 数カ月ぶりに獲物が現れたというのに、友人が満月の夜に予定を入れようとしてくる。合コンの人数が足りないらしいのだが、そんなの知るか。\n指定特技 《逸らす/胴部8》\n成功 うまく言い逃れたが苛々する。待ちきれなくて口の中を噛む。感情属性を「怒り」に設定。\n失敗 狩りのあとで顔を出す約束をしてしまう。普通の日常感覚という奴が蘇り、感情属性を「恐怖」に設定。",
  345. "状況 見間違えようもないモノビーストの足跡をたどり、あなたはこの街まで来た。問題はその足跡が鍵のかかったドアの向こうに続いていることだ。うまく蹴り開けられるだろうか?\n指定特技 《蹴る/脚部4》\n成功 ドアは開き、あなたはその向こうにあるものを見た。感情属性を「恐怖」に設定。\n失敗 足がドアを突き抜けたが開かない。脱出は手間だった。感情属性を「怒り」に設定。",
  346. "状況 悪天候のなか、あなたはモノビーストの出現を待ち続ける。奴を狩るために、色々なものを犠牲にしてきたのだ。しかし……天気が悪い。\n指定特技 《待つ/環境4》\n成功 奴はまだ現れない。天気に呼応するかのようにあなたの気分も暗くなる。感情属性を「恐怖」に設定。\n失敗 耐えきれずその場を去る。こんな思いをするのも全部ヤツのせいだ。感情属性を「怒り」に設定。"
  347. ]
  348. ),
  349. "TK2ET" => DiceTable::Table.new(
  350. "トラッキング遭遇表2nd",
  351. "1D6",
  352. [
  353. "状況 あなたはモノビーストの眼前に立ちふさがり、相手になってやると宣言する。言葉が通じなくとも、喧嘩を売ったことは伝わるはずだ。\n指定特技 《売る/社会6》\n成功 このセッション中、【基本攻撃】の攻撃判定にプラス1の修正が付く。\n失敗 まるで相手にされない。【感情】が2点増加する。",
  354. "状況 あなたは病院で目を覚ます。記憶がはっきりしない。どうやら不覚をとったらしく、裏路地で頭を強打して倒れていたようだ。\n指定特技 《脳/頭部7》\n成功 おぼろげに狩りの理由を思い出してきたような気がする。感情属性が反転する。\n失敗 ランダムにアイテムを1つ失う。無くしたことすら気づかない。",
  355. "状況 夜ごとにモノビーストを追いかける生活が続く中、あなたの腕がうずく。思う存分にふるわれる時が間もないことに気づいているのだろうか。\n指定特技 《逆腕/腕部9》\n成功 このセッション中、練習判定にプラス1の修正がつく。 \n失敗 よく調べたら腕が折れていた。【モラル】が2点減少する。",
  356. "状況 ヤツの捕食をまめに妨害することで、夜の行動範囲を狭めていく。もうすぐ、満月の夜には追い詰めることができるだろう。\n指定特技 《塞ぐ/胴部2》\n成功 その後のことに想いを馳せる。感情属性を好きに変更できる。\n失敗 追い詰める過程で手傷を負う。「重傷」の変調を発動する。",
  357. "状況 ヤツを見つけてからいくつの夜が過ぎ去っただろう。モノビーストの足取りを追って移動を続けるあなたの体力は限界を迎えようとしていた。\n指定特技 《逆脚/脚部9》\n成功 いや、まだいける。【モラル】を2点増加させる。\n失敗 もう足が動かない。【モラル】を2点減少する。",
  358. "状況 モノビーストのねぐらを発見した。問題は人間の匂いに気づいてあたりを嗅ぎ回るヤツからどうやって隠れ、戻るかだ。\n指定特技 《隠れる/環境6》\n成功 じっくりモノビーストを観察する機会を得る。このセッション中、習性調査判定にプラス1の修正がつく。\n失敗 あなたを見つけたモノビーストはこのねぐらを放棄した。感情属性が反転する。"
  359. ]
  360. ),
  361. "TK3ET" => DiceTable::Table.new(
  362. "トラッキング遭遇表3rd",
  363. "1D6",
  364. [
  365. "状況 舞台は整った。やつを追い詰めながら作り上げてきた包囲網は、確実にヤツをあの場所に追い詰めている。急ぐ必要はない。ゆっくりと行こう。\n指定特技 《作る/社会8》\n成功 準備に時間をかけたので、アイテムを一つ入手できる。\n失敗 ゆっくりした結果、モノビーストは何人か犠牲者を増やし、【モラル】を3点増加させている。",
  366. "状況 煌々と輝く月の下、行くべき場所はすでに分かっていた。武器が、体が、夜に満ちる死の予感に震える。決戦の時が来たのだ。\n指定特技 《予感/頭部9》\n成功 日暮れの戦闘フェイズの間、自分が行う全ての攻撃のダメージにプラス1の修正がつく。\n失敗 あれ、いない?あてがはずれた結果、日暮れの追跡フェイズの判定すべてにマイナス2の修正がつく。",
  367. "状況 ついにモノビーストに追いつき、憎しみを込めて殴りつける。この夜の間だけは対等だ。痛みと自分の血の味を知るがいい!\n指定特技 《殴る/腕部3》\n成功 命中!モノビーストの【モラル】を2点減少させる。\n失敗 効いた様子がない。【感情】が2点増加する。",
  368. "状況 ついに追いつめたモノビーストが威嚇とともに襲いかかってくるが、あなたは慌てずにその攻撃を受け止める。驚いた顔のまま死ぬ人間ばかりではないことを教えてやろう。\n指定特技 《受ける/腕部6》\n成功 攻撃を受けてみた結果、感情属性を好きに変更できる。\n失敗 攻撃を受けたときに、「流血」の変調を発動する。",
  369. "状況 ヤツは満月の持つ意味を知っていた。だが、必死に逃げようとするモノビーストにも知らないことはあった。あなたはヤツより速いのだ。\n指定特技 《迫る/脚部2》\n成功 ヤツは動揺している。モノビーストの【感情】が2点増加する。\n失敗 速いはずだがなぜか追いつけない。日暮れの戦闘フェイズの先制判定を行わず、必ず後攻になる。",
  370. "状況 モノビーストの出現ポイントにあたりをつけ、あなたは狩りの前に休息をとる。あの獣を自分の手で殺すため、今は力をたくわえよう。\n指定特技 《休む/環境3》\n成功 英気を養った。【モラル】が2点増加する。\n失敗 じっとしているうちに不安になってきた。感情属性が反転する。"
  371. ]
  372. ),
  373. }.freeze
  374. 1 register_prefix(RTT.prefixes, 'SA', TABLES.keys)
  375. end
  376. end
  377. end

lib/bcdice/game_system/IfIfIf.rb

100.0% lines covered

100.0% branches covered

56 relevant lines. 56 lines covered and 0 lines missed.
8 total branches, 8 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class IfIfIf < Base
  5. 1 ID = "IfIfIf"
  6. # ゲームシステム名
  7. 1 NAME = "イフ・イフ・イフ"
  8. # ゲームシステム名の読みがな
  9. 1 SORT_KEY = "いふいふいふ"
  10. 1 HELP_MESSAGE = <<~TEXT
  11. 100の質問:HQT
  12. ハイリスク歪み表:HDT
  13. ローリスク歪み表:LDT
  14. 「HQT1」「LDT4」のように、表の後ろに数字を付けることで、10個の表から個別に振ることができます。
  15. 致命的な歪みの回避:ID
  16. 改竄判定:IM
  17. 強制改竄判定:IE
  18. TEXT
  19. 1 def eval_game_system_specific_command(command)
  20. 21 return check_action(command) || roll_tables(command, TABLES)
  21. end
  22. 1 def check_action(command)
  23. 21 case command
  24. when: 1 when "ID"
  25. 1 eval_common_command("3TY6")
  26. when: 4 when "IE"
  27. 4 dicearr = @randomizer.roll_barabara(3, 6)
  28. 4 success = dicearr.count(6) == 3
  29. 4 success_count = dicearr.count(6)
  30. 4 then: 1 if success
  31. 1 Result.success("(3B6=6) > #{dicearr.join(',')} > 6の数:#{success_count}")
  32. else: 3 else
  33. 3 Result.failure("(3B6=6) > #{dicearr.join(',')} > 6の数:#{success_count} 不足数:#{3 - success_count}")
  34. end
  35. when: 4 when "IM"
  36. 4 dicearr = @randomizer.roll_barabara(3, 6)
  37. 4 success_count = dicearr.count(6)
  38. 4 then: 1 if success_count == 0
  39. 1 Result.failure("(3B6=6) > #{dicearr.join(',')} > 6の数:#{success_count} 選べるエンド数:#{success_count + 1}")
  40. else: 3 else
  41. 3 Result.success("(3B6=6) > #{dicearr.join(',')} > 6の数:#{success_count} 選べるエンド数:#{success_count + 1}")
  42. end
  43. else: 12 else
  44. 12 return nil
  45. end
  46. end
  47. 1 HQT1 = DiceTable::Table.new(
  48. "100の質問表その1‐印象質問",
  49. "1D10",
  50. [
  51. "相手の好きなところはどこですか?",
  52. "相手の苦手なところはどこですか?",
  53. "相手の尊敬できるところはどこですか?",
  54. "相手の容姿についてどう思っていますか?",
  55. "相手の才能についてどう思っていますか?",
  56. "相手の趣味についてどう思っていますか?",
  57. "相手の価値観についてどう思っていますか?",
  58. "相手について理解できないところはどこですか?",
  59. "相手について心配なところはどこですか?",
  60. "相手の第一印象と今の印象で変化した点はどこですか?",
  61. ]
  62. )
  63. 1 HQT2 = DiceTable::Table.new(
  64. "100の質問表その2‐日常質問",
  65. "1D10",
  66. [
  67. "ふたりの関係性を一言で表すなら?",
  68. "二人の日常はどんな様子ですか?",
  69. "「なんの予定もない、一緒にいる休日」の過ごし方はどんな風ですか?",
  70. "ふたりの最初の出会いはどんな風でしたか?",
  71. "ふたりで食事をするときは、どんな様子ですか?",
  72. "ふたりで買い物をするときは、どんな様子ですか?",
  73. "ふたりで一緒に寝ることはありますか? あるなら、どんな様子ですか?",
  74. "ふたりで最近ハマっていることってありますか?",
  75. "相手といると緊張しますか? 安心しますか?",
  76. "相手への愚痴ってありますか? この際言っちゃいましょう!"
  77. ]
  78. )
  79. 1 HQT3 = DiceTable::Table.new(
  80. "100の質問表その3‐汎用思い出質問",
  81. "1D10",
  82. [
  83. "喧嘩した思い出はありますか? 詳しく語ってください!",
  84. "相手を看病した時の思い出はありますか? 詳しく語ってください!",
  85. "相手からの贈り物で印象深いものはありますか?",
  86. "ふたりで約束してることはありますか? 教えてください!",
  87. "お互いしか知らない秘密はありますか? 教えてください!",
  88. "相手を泣かせた思い出はありますか? 詳しく語ってください!",
  89. "ふたりで犬 or 猫を目の前にしたときの思い出はありますか?詳しく語ってください!",
  90. "ふたりでどこかに閉じ込められた思い出はありますか? 詳しく語ってください!",
  91. "ふたりで旅(旅行)をした思い出はありますか? 詳しく語ってください!",
  92. "ふたりでいてドキドキした思い出はありますか? 詳しく語ってください!",
  93. ]
  94. )
  95. 1 HQT4 = DiceTable::Table.new(
  96. "100の質問表その4‐情景思い出質問",
  97. "1D10",
  98. [
  99. "ふたりで夜明けを迎えたときの思い出を語ってくれますか?",
  100. "ふたりで星を見た思い出を語ってくれますか?",
  101. "ふたりで海に行った思い出を語ってくれますか?",
  102. "ふたりで暗闇で過ごした思い出を語ってくれますか?",
  103. "ふたりで炎に巻かれた思い出を語ってくれますか?",
  104. "ふたりで花畑で過ごした思い出を語ってくれますか?",
  105. "ふたりで森で過ごした思い出を語ってくれますか?",
  106. "ふたりで砂漠を歩いた思い出を語ってくれますか?",
  107. "ふたりで廃墟を歩いた思い出をかたってくれますか?",
  108. "ふたりで突然雨に降られたときの思い出を語ってくれますか?",
  109. ]
  110. )
  111. 1 HQT5 = DiceTable::Table.new(
  112. "100の質問表その5‐内緒の質問(オフレコ推奨)",
  113. "1D10",
  114. [
  115. "相手に絶対に知られたくない秘密ってありますか? 教えてください!",
  116. "相手に嘘をついていることはありますか? 教えてください!",
  117. "相手に知られたら引かれそうなことってありますか? 教えてください!",
  118. "相手に知られたら怒られそうなことってありますか? 教えてください!",
  119. "相手に知られたら嫌われそうなことってありますか? 教えてください!",
  120. "相手に関して正直ちょっと引いたことはありますか? どんなことですか?",
  121. "相手に恋した瞬間は、どんな感じでしたか?",
  122. "相手について密かに妄想してることはありますか? 教えてください!",
  123. "相手について「大っぴらに言うのははばかられるけど、好きなところ」ってありますか? 教えてください!",
  124. "相手に懺悔したいことはありますか? どんなことですか?",
  125. ]
  126. )
  127. 1 HQT6 = DiceTable::Table.new(
  128. "100の質問表その6‐ブラック質問1",
  129. "1D10",
  130. [
  131. "相手に嫌われたらどうしますか?",
  132. "相手を傷つけたことはありますか? どんなことですか?",
  133. "相手を傷つけたいと思ったことはありますか?",
  134. "相手と殺し合ったことはありますか? そのときのことを教えてください。",
  135. "相手を殺したいと思ったことはありますか? そのときのことを教えてください。",
  136. "相手に嫉妬していることはありますか? どんなことですか?",
  137. "相手を憎んでいることはありますか? どんなことですか?",
  138. "相手に自分以外の恋人が出来たらどうしますか?",
  139. "相手が死んだら自分はどうしますか?",
  140. "自分が死んだら相手にどうしてもらいたいですか?",
  141. ]
  142. )
  143. 1 HQT7 = DiceTable::Table.new(
  144. "100の質問表その7‐ブラック質問2",
  145. "1D10",
  146. [
  147. "相手と出会ってなかったら今頃どうなってたと思いますか?",
  148. "相手には、あなた以外にどんな人がふさわしいと思いますか?",
  149. "相手について怖いと思うところはどこですか?",
  150. "相手と自分の命、どっちのほうが大事ですか?",
  151. "相手のために、犯罪を犯すことはできますか?",
  152. "相手が犯罪者になってしまったらどうしますか?",
  153. "相手が完全な記憶喪失になったらどうしますか?",
  154. "相手が自分を忘れるのと、自分が相手を忘れるのだと、どちらがマシですか?",
  155. "相手に「死んでほしい」と言われたらどうしますか?",
  156. "相手に「殺して欲しい」と頼まれたらどうしますか?",
  157. ]
  158. )
  159. 1 HQT8 = DiceTable::Table.new(
  160. "100の質問表その8‐雑談質問",
  161. "1D10",
  162. [
  163. "相手に対して、自分が自慢できるのはどんなところですか?",
  164. "相手の寝相についてどう思いますか?",
  165. "ふたりの体格差って、どんな感じですか?",
  166. "ふたりとも、幽霊って信じてますか?",
  167. "ふたりは自炊派? 外食派?",
  168. "ふたりは辛党? 甘党?",
  169. "お互いの家族構成、知ってますか? 知らないなら教え合いましょう!",
  170. "相手のファッション(普段の服装)について、どう思いますか?",
  171. "相手に手料理を食べさせたことはありますか?",
  172. "相手がコーヒーや紅茶にお砂糖何杯入れるか、知ってますか?",
  173. ]
  174. )
  175. 1 HQT9 = DiceTable::Table.new(
  176. "100の質問表その9‐ファンタジー質問",
  177. "1D10",
  178. [
  179. "相手の種族についてどう思いますか?",
  180. "相手の魔法についてどう思いますか?",
  181. "相手の戦闘能力についてどう思いますか?",
  182. "戦場にいるときの相手の雰囲気についてどう思いますか?",
  183. "相手の特殊能力(戦闘面以外)についてどう思いますか?",
  184. "ふたりには、なにか二つ名や称号はありますか? それについてどう思いますか?",
  185. "お互いの身分についてどう思いますか?",
  186. "ふたりに寿命差はありますか? ある場合は、どう考えていますか?",
  187. "ふたりで敵に襲われたときの思い出を語ってくれますか?",
  188. "相手とダンジョンに行った思い出を語ってくれますか?",
  189. ]
  190. )
  191. 1 HQT10 = DiceTable::Table.new(
  192. "100の質問表その10‐現代質問",
  193. "1D10",
  194. [
  195. "お互い、どんな学校に通っていますか/通っていましたか?",
  196. "SNSってやっていますか? お互いのアカウントって知ってますか?",
  197. "ふたりで映画を見るなら、どんなジャンルですか? そのジャンルは1人で見るときと違いますか?",
  198. "ふたりでテーマパークに行った思い出はありますか? 詳しく教えてください!",
  199. "ふたりはよくメールや電話で連絡をとりますか?",
  200. "お互いの写真って持っていますか? 持っているなら、どんな写真ですか?",
  201. "ふたりでカラオケに行きますか? 行くならどんな様子ですか?",
  202. "ふたりで行きたい観光名所はありますか? 具体的な地名で教えてください!",
  203. "ふたりが好きな季節はいつですか?",
  204. "目玉焼きに何をかけますか?(塩、醤油、ソース、マヨネーズ……)",
  205. ]
  206. )
  207. 1 LDT1 = DiceTable::Table.new(
  208. "ローリスク歪み表:名前、性別、年齢、人称",
  209. "1D10",
  210. [
  211. "ミドルネームが増える",
  212. "周囲からあだ名で呼ばれるようになる",
  213. "人に変なあだ名をつける癖ができる",
  214. "異性装が趣味になる",
  215. "理由あって異性として生活していることになる",
  216. "これ以降、外見年齢があまり変わらなくなる",
  217. "10歳若返る",
  218. "10歳歳を取る",
  219. "一人称が変わる",
  220. "二人称が変わる",
  221. ]
  222. )
  223. 1 LDT2 = DiceTable::Table.new(
  224. "ローリスク歪み表:外見的特徴",
  225. "1D10",
  226. [
  227. "片目の色が変化する",
  228. "両目の色が変化する",
  229. "髪の色が変化する",
  230. "髪が癖毛(天然パーマ、猫っ毛など)になる",
  231. "髪の長さが変わる(長髪なら短髪に、短髪なら長髪に)",
  232. "他者から「美人」と言われる外見になる",
  233. "眼鏡キャラになる(伊達眼鏡でも可)",
  234. "特徴的なファッションになる(ゴスロリ、赤一色、常に白衣など)",
  235. "身長が10cm大きくなる",
  236. "身長が10cm小さくなる",
  237. ]
  238. )
  239. 1 LDT3 = DiceTable::Table.new(
  240. "ローリスク歪み表:性格",
  241. "1D10",
  242. [
  243. "あらゆることに対する思い切りがよくなる",
  244. "思考や発想が幼くなる",
  245. "初対面の人と上手く話せなくなる",
  246. "感情の起伏が激しくなる",
  247. "感情を抑えがちになる",
  248. "泣き虫になる",
  249. "よく人に甘えるようになる",
  250. "とてつもなくポジティブになる",
  251. "天邪鬼になりがちになる",
  252. "自分を卑下しがちになる",
  253. ]
  254. )
  255. 1 LDT4 = DiceTable::Table.new(
  256. "ローリスク歪み表:得意不得意",
  257. "1D10",
  258. [
  259. "得意不得意が逆転する",
  260. "運動がすごく得意になる",
  261. "芸術関係(絵、音楽、書道など)が得意になる",
  262. "感情を隠すのが下手になる",
  263. "手先が器用になる",
  264. "料理が壊滅的に下手になる",
  265. "四則演算が苦手になる",
  266. "人の真似が上手になる",
  267. "役に立たない特技ができる",
  268. "一般的にあり得ない異能(超能力など)に目覚める",
  269. ]
  270. )
  271. 1 LDT5 = DiceTable::Table.new(
  272. "ローリスク歪み表:社会的立場",
  273. "1D10",
  274. [
  275. "転校/転職したことになる(元居た学校や職場でなくなる)",
  276. "自分のファンクラブが出来る",
  277. "学校/仕事の成績が大幅に向上する",
  278. "学校/仕事の成績が大幅に低下する",
  279. "賃金/お小遣いが下がる",
  280. "他人から妙に頼られるようになる",
  281. "自分に関する悪い噂が流れるようになる",
  282. "大金持ちになる",
  283. "ガラが悪い人々(不良、裏稼業など)と繋がっていることになる",
  284. "誰もが知っている有名人になる",
  285. ]
  286. )
  287. 1 LDT6 = DiceTable::Table.new(
  288. "ローリスク歪み表:パートナーとの関係性や呼び方",
  289. "1D10",
  290. [
  291. "パートナーと恋仲だったことになる",
  292. "パートナーとお互いに特別な名前で呼び合うようになる",
  293. "パートナーと寝室が一緒になる",
  294. "パートナーと家族だったことになる",
  295. "パートナーとの身体的スキンシップが増える",
  296. "パートナーと家族ぐるみの付き合いになる",
  297. "自分がパートナーに精神的に依存する",
  298. "パートナーが自分に精神的に依存する",
  299. "パートナーを傷つけたくてたまらなくなる",
  300. "パートナーが好きで好きでたまらなくなる",
  301. ]
  302. )
  303. 1 LDT7 = DiceTable::Table.new(
  304. "ローリスク歪み表:現在の生活",
  305. "1D10",
  306. [
  307. "近づくと赤ちゃんがギャン泣きする体質になる",
  308. "義理の家族がある",
  309. "仕事や学業などに忙殺される生活になる",
  310. "体調を崩しがちになる(貧血、流行病など)",
  311. "家族以外の誰かと同居していることになる(シェアハウス、同棲など)",
  312. "何らかの嗜好品(酒、煙草、甘味など)がやめられなくなる",
  313. "住居が雨漏りするようになる",
  314. "住居に心霊現象が発生するようになる",
  315. "近所の猫に嫌われる",
  316. "金遣いが荒くなる",
  317. ]
  318. )
  319. 1 LDT8 = DiceTable::Table.new(
  320. "ローリスク歪み表:過去",
  321. "1D10",
  322. [
  323. "昔いじめられていたことになる",
  324. "以前なにかで表彰されたことになる",
  325. "以前グレていた時期があったことになる",
  326. "誰かにお金を借りていたことになる",
  327. "幼い頃、家出したことがあったことになる",
  328. "以前誰かに告白して、フラれたことになる",
  329. "幼い頃、体が弱かったことになる",
  330. "以前すごく中二病だったことになる",
  331. "南国で親父に〇〇(任意の特殊技能)を習っていたことになる",
  332. "誰かとの約束を忘れる",
  333. ]
  334. )
  335. 1 LDT9 = DiceTable::Table.new(
  336. "ローリスク歪み表:自由欄1",
  337. "1D10",
  338. [
  339. "性癖が歪む",
  340. "ドジっ子属性がつく",
  341. "人の声が聞き取りにくくなる",
  342. "落ちている硬貨に必ず気づくようになる",
  343. "人の顔を覚えるのが苦手になる",
  344. "とても寒がりになる",
  345. "血を見るのが怖くなる",
  346. "ピーマンが苦手になる",
  347. "動物にやけに好かれるようになる",
  348. "暗いところが怖くなる",
  349. ]
  350. )
  351. 1 LDT10 = DiceTable::Table.new(
  352. "ローリスク歪み表:自由欄2",
  353. "1D10",
  354. [
  355. "寝床に入ると数秒で寝落ちするようになる",
  356. "全裸でないと寝られなくなる",
  357. "見えないはずのものが見える様になる",
  358. "財布を忘れがちになる",
  359. "子供を見ると可愛がらざるを得なくなる",
  360. "夜眠れなくなる",
  361. "特徴的な口癖ができる",
  362. "掃除好きになる",
  363. "お年寄りにやけに好かれるようになる",
  364. "スリルを感じるのが快感になる",
  365. ]
  366. )
  367. 1 HDT1 = DiceTable::Table.new(
  368. "ハイリスク歪み表:名前、性別、年齢、人称",
  369. "1D10",
  370. [
  371. "名前の綴り、あるいは漢字が変化する",
  372. "名前の音が変わる",
  373. "名無しとなり、誰も元の名前を思い出せなくなる",
  374. "生まれた時から異性だったことになる",
  375. "後天的に性別が異性に変化する",
  376. "これ以降一切歳をとらなくなる",
  377. "外見年齢が歳をとる",
  378. "外見年齢が幼くなる",
  379. "一人称が変化する",
  380. "二人称が変化する",
  381. ]
  382. )
  383. 1 HDT2 = DiceTable::Table.new(
  384. "ハイリスク歪み表:外見的特徴",
  385. "1D10",
  386. [
  387. "片目の色が変化する",
  388. "両目の色が変化する",
  389. "髪の色が変化する",
  390. "全身から色素が抜け落ちる(アルビノ化)",
  391. "角が生える/もとが有角の場合は角を失う",
  392. "体の一部が獣のようになる/元が獣型の場合はヒトの形となる",
  393. "翼が生える/元が有翼の場合は翼を失う",
  394. "体の一部が人形のようになる/元が人形の場合は人と変わらぬ姿になる",
  395. "体の何処かに大きな傷が出来る",
  396. "体の何処かを欠損する",
  397. ]
  398. )
  399. 1 HDT3 = DiceTable::Table.new(
  400. "ハイリスク歪み表:性格",
  401. "1D10",
  402. [
  403. "性格が攻撃的になる",
  404. "思考や発想が幼くなる",
  405. "疑心暗鬼になる",
  406. "感情の起伏が激しくなる",
  407. "感情の起伏が無くなる",
  408. "泣き虫になる",
  409. "よく人に甘えるようになる",
  410. "とてつもなくポジティブになる",
  411. "倫理観が欠如する",
  412. "特定の感情を喪失する",
  413. ]
  414. )
  415. 1 HDT4 = DiceTable::Table.new(
  416. "ハイリスク歪み表:得意不得意",
  417. "1D10",
  418. [
  419. "得意不得意が逆転する",
  420. "戦闘能力を失う/高負荷の運動ができなくなる",
  421. "芸術関係(絵、音楽、書道など)が得意になる",
  422. "感情を隠すのが下手になる",
  423. "感覚が異様に鋭敏になる",
  424. "料理が壊滅的に下手になる",
  425. "四則演算が苦手になる",
  426. "特異な才能が開花する",
  427. "才能をひとつ失う",
  428. "一般的にあり得ない異能(超能力など)に目覚める",
  429. ]
  430. )
  431. 1 HDT5 = DiceTable::Table.new(
  432. "ハイリスク歪み表:社会的立場",
  433. "1D10",
  434. [
  435. "職を失う",
  436. "周囲から崇められる立場になる",
  437. "学校/仕事の成績が大幅に向上する",
  438. "戸籍上死者になる",
  439. "借金まみれになる",
  440. "多くの人に慕われる人気者になる",
  441. "犯罪者として扱われる",
  442. "大金持ちになる",
  443. "何らかの組織に追われる身になる",
  444. "誰もが知っている有名人になる",
  445. ]
  446. )
  447. 1 HDT6 = DiceTable::Table.new(
  448. "ハイリスク歪み表:パートナーとの関係性や呼び方",
  449. "1D10",
  450. [
  451. "パートナーと恋仲だったことになる",
  452. "パートナーとお互いに特別な名前で呼び合うようになる",
  453. "パートナーに憎まれる",
  454. "パートナーと家族だったことになる",
  455. "パートナーから忘れられる",
  456. "パートナーの言葉に逆らえなくなる",
  457. "自分がパートナーに精神的に依存する",
  458. "パートナーが自分に精神的に依存する",
  459. "パートナーを傷つけたくてたまらなくなる",
  460. "パートナーが好きで好きでたまらなくなる",
  461. ]
  462. )
  463. 1 HDT7 = DiceTable::Table.new(
  464. "ハイリスク歪み表:現在の生活",
  465. "1D10",
  466. [
  467. "住居が崩壊する",
  468. "身に覚えがない子供ができる",
  469. "仕事や学業などに忙殺される生活になる",
  470. "体調を崩しがちになる(貧血、流行病など)",
  471. "住んでいる町(村、国)が滅びる",
  472. "何らかの嗜好品(酒、煙草、甘味など)がやめられなくなる",
  473. "故郷が滅びたことになる",
  474. "パートナー以外の人がいる場所が怖くなる",
  475. "住んでいる場所が戦場になる",
  476. "不治の病にかかる",
  477. ]
  478. )
  479. 1 HDT8 = DiceTable::Table.new(
  480. "ハイリスク歪み表:過去",
  481. "1D10",
  482. [
  483. "かつて誰かを殺したことになる",
  484. "過去の功績がひとつなくなる",
  485. "過去のすべての記憶を失う",
  486. "かつてパートナーを傷つけたことがある",
  487. "幼い頃、自分以外の家族全員が死亡した",
  488. "以前誰かに告白して、フラれたことになる",
  489. "犯罪歴ができる",
  490. "大切な思い出がひとつなかったことになる",
  491. "悲しい思い出がひとつ増える",
  492. "誰かとの約束を忘れる",
  493. ]
  494. )
  495. 1 HDT9 = DiceTable::Table.new(
  496. "ハイリスク歪み表:自由欄1",
  497. "1D10",
  498. [
  499. "パートナー以外の人の顔が塗りつぶされて見える",
  500. "色覚を失う",
  501. "声を失う",
  502. "誰かと目を合わせることが怖くなる",
  503. "零した涙が宝石になる",
  504. "体の一部に植物が生える",
  505. "血を見るのが怖くなる",
  506. "血を見ることに悦びを覚えるようになる",
  507. "動物にやけに好かれるようになる",
  508. "人に触れるのが怖くなる",
  509. ]
  510. )
  511. 1 HDT10 = DiceTable::Table.new(
  512. "ハイリスク歪み表:自由欄2",
  513. "1D10",
  514. [
  515. "人の血を啜りたくなる",
  516. "失明する",
  517. "見えないはずのものが見える様になる",
  518. "水に浸かると人魚になってしまう",
  519. "鏡や写真にうつらなくなる",
  520. "夜眠れなくなる",
  521. "影が無くなる",
  522. "味覚が鈍くなる",
  523. "痛覚が鈍くなる",
  524. "意味もなく急に涙があふれるようになる",
  525. ]
  526. )
  527. TABLES = {
  528. 1 "HQT" => DiceTable::ChainTable.new(
  529. "100の質問",
  530. "1D10",
  531. [
  532. HQT1,
  533. HQT2,
  534. HQT3,
  535. HQT4,
  536. HQT5,
  537. HQT6,
  538. HQT7,
  539. HQT8,
  540. HQT9,
  541. HQT10,
  542. ]
  543. ),
  544. "LDT" => DiceTable::ChainTable.new(
  545. "ローリスク歪み表",
  546. "1D10",
  547. [
  548. LDT1,
  549. LDT2,
  550. LDT3,
  551. LDT4,
  552. LDT5,
  553. LDT6,
  554. LDT7,
  555. LDT8,
  556. LDT9,
  557. LDT10,
  558. ]
  559. ),
  560. "HDT" => DiceTable::ChainTable.new(
  561. "ハイリスク歪み表",
  562. "1D10",
  563. [
  564. HDT1,
  565. HDT2,
  566. HDT3,
  567. HDT4,
  568. HDT5,
  569. HDT6,
  570. HDT7,
  571. HDT8,
  572. HDT9,
  573. HDT10,
  574. ]
  575. ),
  576. "HQT1" => HQT1,
  577. "HQT2" => HQT2,
  578. "HQT3" => HQT3,
  579. "HQT4" => HQT4,
  580. "HQT5" => HQT5,
  581. "HQT6" => HQT6,
  582. "HQT7" => HQT7,
  583. "HQT8" => HQT8,
  584. "HQT9" => HQT9,
  585. "HQT10" => HQT10,
  586. "HDT1" => HDT1,
  587. "HDT2" => HDT2,
  588. "HDT3" => HDT3,
  589. "HDT4" => HDT4,
  590. "HDT5" => HDT5,
  591. "HDT6" => HDT6,
  592. "HDT7" => HDT7,
  593. "HDT8" => HDT8,
  594. "HDT9" => HDT9,
  595. "HDT10" => HDT10,
  596. "LDT1" => LDT1,
  597. "LDT2" => LDT2,
  598. "LDT3" => LDT3,
  599. "LDT4" => LDT4,
  600. "LDT5" => LDT5,
  601. "LDT6" => LDT6,
  602. "LDT7" => LDT7,
  603. "LDT8" => LDT8,
  604. "LDT9" => LDT9,
  605. "LDT10" => LDT10,
  606. }.freeze
  607. 1 register_prefix('ID', 'IE', 'IM', TABLES.keys)
  608. end
  609. end
  610. end

lib/bcdice/game_system/Illusio.rb

100.0% lines covered

90.0% branches covered

36 relevant lines. 36 lines covered and 0 lines missed.
10 total branches, 9 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Illusio < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Illusio'
  7. # ゲームシステム名
  8. 1 NAME = '晃天のイルージオ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'こうてんのいるうしお'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. 判定:[n]IL(BNo)[P]
  14. []内のコマンドは省略可能。
  15. 「n」でダイス数を指定。省略時は「1」。
  16. (BNo)でブロックナンバーを指定。「236」のように記述。順不同可。
  17. コマンド末に「P」を指定で、(BNo)のパリィ判定。(一応、複数指定可)
  18. 【書式例】
  19. ・6IL236 → 6dでブロックナンバー「2,3,6」の判定。
  20. ・IL4512 → 1dでブロックナンバー「1,2,4,5」の判定。
  21. ・2IL1P → 2dでパリィナンバー「1」の判定。
  22. MESSAGETEXT
  23. 1 def initialize(command)
  24. 9 super(command)
  25. 9 @sort_add_dice = true # ダイスのソート有
  26. end
  27. 1 register_prefix(
  28. '(\d+)?IL([1-6]{0,6})(P)?'
  29. )
  30. 1 def eval_game_system_specific_command(command)
  31. 9 m = command.match(/(\d+)?IL([1-6]{0,6})(P)?$/i)
  32. 9 else: 9 then: 0 return nil unless m
  33. 9 dice_count = (m[1] || 1).to_i
  34. 9 block_no = (m[2] || "").each_char.map(&:to_i).uniq.sort
  35. 9 is_parry = !m[3].nil?
  36. 9 return check_roll(dice_count, block_no, is_parry)
  37. end
  38. 1 def check_roll(dice_count, block_no, is_parry)
  39. 9 dice_array = @randomizer.roll_barabara(dice_count, 6).sort
  40. 9 dice_text = dice_array.join(',')
  41. 9 result_array = []
  42. 9 success = 0
  43. 9 dice_array.each do |i|
  44. 30 then: 14 if block_no.count(i) > 0
  45. 14 result_array.push("×")
  46. else: 16 else
  47. 16 result_array.push(i)
  48. 16 success += 1
  49. end
  50. end
  51. 9 block_text = block_no.join(',')
  52. 9 then: 2 else: 7 block_text2 = is_parry ? "Parry" : "Block"
  53. 9 result_text = result_array.join(',')
  54. 9 result = "#{dice_count}D6(#{block_text2}:#{block_text}) > #{dice_text} > #{result_text} > "
  55. 9 else: 2 then: 7 return "#{result}成功数:#{success}" unless is_parry
  56. 2 then: 1 if success < dice_count
  57. 1 "#{result}パリィ成立! 次の非ダメージ2倍。"
  58. else: 1 else
  59. 1 "#{result}成功数:#{success} パリィ失敗"
  60. end
  61. end
  62. end
  63. end
  64. end

lib/bcdice/game_system/InfiniteBabeL.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/ShoujoTenrankai"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class InfiniteBabeL < ShoujoTenrankai
  6. # ゲームシステムの識別子
  7. 1 ID = "InfiniteBabeL"
  8. # ゲームシステム名
  9. 1 NAME = "少年のための少女展爛会異聞 Infinite BabeL"
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = "しようねんのためのしようしよてんらんかいいふんいんふいにつとはへる"
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~MESSAGETEXT
  14. ■ 一日の出来事表
  15. HOT 暑い日
  16. COLD 寒い日
  17. MORNING 朝
  18. NOON 昼
  19. AFTERNOON 昼下がり
  20. TWILIGHT 黄昏
  21. NIGHT 夜中
  22. MIDNIGHT 夜更け
  23. ■ 場所の出来事表 -アバウト
  24. LARGE 広い場所
  25. ALLEY 路地
  26. STAIRS 階段
  27. COSY 居心地のいい場所
  28. SKY 空が見える場所
  29. BATH 浴室
  30. BOTANY 植物がある場所
  31. WAHER 水がある場所
  32. DIM 薄暗い場所
  33. FIRE 火がある場所
  34. LABO ラボトラリー
  35. BED 寝室
  36. ■ 場所の出来事表 -表立った場所
  37. CHIMNEY 煙突街
  38. LIBRARY ライブラリー
  39. SLUM スラム
  40. JUNKYARD ジャンクヤード
  41. IROMACHI イロマチ
  42. MONASTERY 修道院
  43. ROSE ローズガーデン
  44. MESSAGETEXT
  45. EVENT_TABLES = {
  46. 1 "HOT" => {
  47. name: "暑い日",
  48. table: [
  49. "【奇・1】透明な汗が、するりと頬を伝い落ちていった。",
  50. "【奇・2】暑さが気だるくてイマイチやる気が起きない。(ロゴス +1)",
  51. "【奇・3】涼やかな水の音が聞こえた気がする。",
  52. "【奇・4】やたらに喉が渇いている。",
  53. "【奇・5】生ぬるい風が首筋の辺りをなぞっていった。",
  54. "【奇・6】なんか妙にハイになってきた。(パトス +1)",
  55. "【偶・1】蜃気楼の向こうの景色が揺らめいている。",
  56. "【偶・2】自分と世界の境界があいまいになってきた。(エロス +1)",
  57. "【偶・3】不意に息苦しくなった。",
  58. "【偶・4】遠くから誰かの笑い声が聞こえた気がした。",
  59. "【偶・5】不思議と寒気が止まらない。",
  60. "【偶・6】何か鈍い音が聞こえた気がする。(タナトス +1)",
  61. ]
  62. },
  63. "COLD" => {
  64. name: "寒い日",
  65. table: [
  66. "【奇・1】なんだか無性にとてつもなく、人肌が恋しい。(エロス +1)",
  67. "【奇・2】気がついたら指の感覚がなくなっていた。",
  68. "【奇・3】吐き出した息が白くなって消えた。",
  69. "【奇・4】なんだか眠たくなってきた。(タナトス +1)",
  70. "【奇・5】冷たい風が吹き抜けていった。",
  71. "【奇・6】水が少し凍っているようだ。",
  72. "【偶・1】暖かい空気が、壁の隙間から漏れている。",
  73. "【偶・2】やたらと爽快な気分だ。",
  74. "【偶・3】ぞくりと背筋に寒気が走った。",
  75. "【偶・4】立派な【氷柱 ( 純押 )】(ウェポン)が下がっている。",
  76. "【偶・5】一瞬、耳が痛くなるほどの静寂が張り詰めた。(ロゴス +1)",
  77. "【偶・6】凍ったところを踏んで、滑ってコケた。(パトス +1)",
  78. ]
  79. },
  80. "MORNING" => {
  81. name: "朝",
  82. table: [
  83. "【奇・1】起きたら涙を流していた。",
  84. "【奇・2】眠っていた時とは別の場所で目覚めた。(エロス +1)",
  85. "【奇・3】寝相が悪かったのか、痛い思いをして目を覚ました。(パトス +1)",
  86. "【奇・4】結露のしずくが目に留まった。",
  87. "【奇・5】誰かが騒いでいるような声と物音が聞こえる。",
  88. "【奇・6】まだかなり眠い。",
  89. "【偶・1】むやみに爽快な気分だ。",
  90. "【偶・2】体が強張っていて、くたびれた感じがする。(タナトス +1)",
  91. "【偶・3】ひどく喉が渇いている。",
  92. "【偶・4】朝もやが出たらしく、景色が白く霞がかって見える。(ロゴス +1)",
  93. "【偶・5】夢から醒めたが、どんな夢か覚えていない。",
  94. "【偶・6】周囲の音がやけに鮮明に耳に響いている。",
  95. ]
  96. },
  97. "NOON" => {
  98. name: "昼",
  99. table: [
  100. "【奇・1】なんだかじっとしていられない。",
  101. "【奇・2】奇妙なだるさを感じている。(エロス +1)",
  102. "【奇・3】ひどくお腹が空いている。",
  103. "【奇・4】どこからか食事の匂いがする。",
  104. "【奇・5】照明が消えそうで消えず、チカチカしている。",
  105. "【奇・6】なんだか無性にいらいらする。",
  106. "【偶・1】世界に自分だけが取り残されたような気分になった。(ロゴス +1)",
  107. "【偶・2】変に草木の緑が目に付く気がする。(タナトス +1)",
  108. "【偶・3】なんだか急に、寒気を感じた。",
  109. "【偶・4】さっぱりやる気が起きない。",
  110. "【偶・5】賑やかな話し声が聞こえてくる気がする。",
  111. "【偶・6】目に触れるあらゆるものが輝いて見えるような気がする。(パトス +1)",
  112. ]
  113. },
  114. "AFTERNOON" => {
  115. name: "昼下がり",
  116. table: [
  117. "【奇・1】壮絶に気持ちよく眠い。",
  118. "【奇・2】軽く腹がへった。",
  119. "【奇・3】急に水が上から降ってきた。",
  120. "【奇・4】壁の隙間から光が漏れている。",
  121. "【奇・5】どこかから甘い匂いが漂ってきた。",
  122. "【奇・6】なーんか気だるくて、憂鬱。(エロス +1)",
  123. "【偶・1】力が有り余っている感じがする。",
  124. "【偶・2】今まで動いていた空気の流れがぴたっと止まった。",
  125. "【偶・3】太陽の香りがする。(パトス +1)",
  126. "【偶・4】一陣の風が吹きすぎていきました。",
  127. "【偶・5】何か重たいものが落ちた音がした。(タナトス +1)",
  128. "【偶・6】視線を感じた。(ロゴス +1)",
  129. ]
  130. },
  131. "TWILIGHT" => {
  132. name: "黄昏",
  133. table: [
  134. "【奇・1】人影を見たような気がする。",
  135. "【奇・2】やけに色が薄く感じられ、なにもかもが灰色に見える。(タナトス +1)",
  136. "【奇・3】空気が張り詰めるのを感じた。",
  137. "【奇・4】ふと、自分の影が気になって見つめてしまった。(ロゴス +1)",
  138. "【奇・5】窓ガラスか何かが、光を照り返して輝いている。",
  139. "【奇・6】雑踏や葉ずれの音がやけに大きくざわめいている。",
  140. "【偶・1】灯りが灯った瞬間を見た。(パトス +1)",
  141. "【偶・2】物陰に夜の気配がわだかまっている。",
  142. "【偶・3】蝙蝠の影らしきものが音も無く舞っている。",
  143. "【偶・4】天井を走る鉄のパイプの上にびっしりと鳥のような影が身を寄せ合っている。",
  144. "【偶・5】むやみに月が大きく見える。",
  145. "【偶・6】物の境目が曖昧で、全てが溶けて混ざり合ってしまいそうな気がする。(エロス +1)",
  146. ]
  147. },
  148. "NIGHT" => {
  149. name: "夜中",
  150. table: [
  151. "【奇・1】目が冴えて寝れない。",
  152. "【奇・2】すごい眠い。めちゃくちゃ眠い。本当に眠い。",
  153. "【奇・3】灯った明かりがやけに遠く感じられる。",
  154. "【奇・4】なんか妙に気分が盛り上がってまいりましたよ?(パトス +1)",
  155. "【奇・5】不意に人肌が恋しく感じた。(エロス +1)",
  156. "【奇・6】灯していた明かりがざわめくように揺らいでいる。",
  157. "【偶・1】映し出された影が、やけに大きく見える。",
  158. "【偶・2】ここではないどこか、帰る場所があるような気がする。(タナトス +1)",
  159. "【偶・3】どこからか談笑の声が聞こえた気がする。(ロゴス +1)",
  160. "【偶・4】何かが小さく光った気がする。",
  161. "【偶・5】コトリと硬い音がした。",
  162. "【偶・6】どこからかとても美味しそうな匂いが漂ってくる。",
  163. ]
  164. },
  165. "MIDNIGHT" => {
  166. name: "夜明け",
  167. table: [
  168. "【奇・1】時計の音がやけに大きく響いている。(タナトス +1)",
  169. "【奇・2】夢を見てた気がするけど、どんな夢だったか忘れた。",
  170. "【奇・3】足音を聞いた気がする。",
  171. "【奇・4】ぼそぼそと話す声を聞いた気がする。(ロゴス +1)",
  172. "【奇・5】めっちゃくちゃのどがかわいた。",
  173. "【奇・6】ひどくお腹が空いている。(パトス +1)",
  174. "【偶・1】……寝苦しい。",
  175. "【偶・2】ぜんっぜん、そりゃもうびっくりするくらい、眠くない。",
  176. "【偶・3】ひそやかな笑い声が聞こえた気がする。(エロス +1)",
  177. "【偶・4】見慣れたものの影が全く別のものに見えた。",
  178. "【偶・5】闇がやけに深く感じられる。",
  179. "【偶・6】違和感のある香りがする。",
  180. ]
  181. },
  182. "LARGE" => {
  183. name: "広い場所",
  184. table: [
  185. "【奇・1】誰もいない、何もない虚空に投げ出されたような気分になった",
  186. "【奇・2】誰かの残り香が、ほのかに甘く漂っている。(エロス +1)",
  187. "【奇・3】どこかで扉が開いたような音がしたが、周囲は静まり返っている。",
  188. "【奇・4】自分の足音がやけに大きく響き渡った。",
  189. "【奇・5】ふともらした独り言が、誰に聞かれるでもなく消えていった。(ロゴス +1)",
  190. "【奇・6】塔の天井が軋んだ気がする。(タナトス +1)",
  191. "【偶・1】片隅に、壊れたオブジェが打ち捨てられている。",
  192. "【偶・2】掃除道具が無造作に転がっている。",
  193. "【偶・3】床に派手な傷がついている。",
  194. "【偶・4】誰かにむしられた花がしおしおになって落ちてる。",
  195. "【偶・5】不意に空気が揺れ動くのを感じた。",
  196. "【偶・6】建物の壁に、大きなラクガキがある。(パトス +1)",
  197. ]
  198. },
  199. "ALLEY" => {
  200. name: "路地",
  201. table: [
  202. "【奇・1】窓が開け放たれている。",
  203. "【奇・2】パタン、と扉の閉まる音がした。",
  204. "【奇・3】人影が、向こうの曲がり角に姿を消したような気がする。(パトス +1)",
  205. "【奇・4】街灯が割れている。",
  206. "【奇・5】天井にできたしみのようなものに、ふと目を奪われた。",
  207. "【奇・6】壁に掛けられた絵がわずかに傾いている。",
  208. "【偶・1】永遠の愛を誓う落書きを見つけた。(エロス +1)",
  209. "【偶・2】はしごが朽ちている。",
  210. "【偶・3】いつもの道のはずが、行き止まりにぶち当たった。(タナトス +1)",
  211. "【偶・4】自分の立てた音がやけに大きく耳に残った。(ロゴス +1)",
  212. "【偶・5】誰かの落し物(グッズ APT 打表 )らしきものが落ちている。",
  213. "【偶・6】空っぽのゴミ箱が置かれている。",
  214. ]
  215. },
  216. "STAIRS" => {
  217. name: "階段",
  218. table: [
  219. "【奇・1】暗く、冷たく、静まり返っている。",
  220. "【奇・2】手すりが使い込まれたつややかな輝きを放っている。(パトス +1)",
  221. "【奇・3】手すりの一部が壊れている。",
  222. "【奇・4】重いものをぶつけた痕が残っている。",
  223. "【奇・5】靴が片方(グッズ APT 従純)残されている。(エロス +1)",
  224. "【奇・6】段が嫌な音を立てて大きくきしんだ。",
  225. "【偶・1】隅に埃がたまっている。",
  226. "【偶・2】なぜか、壊れた家具が階段の途中に積み上げてある。",
  227. "【偶・3】上の階から誰かの足音が聞こえてくる。",
  228. "【偶・4】下の階からぼそぼそと声が聞こえたような気がする。(ロゴス +1)",
  229. "【偶・5】壁の隙間から差し込む外の光が段に複雑な陰影を作っている。(タナトス +1)",
  230. "【偶・6】一段踏み外した。",
  231. ]
  232. },
  233. "COSY" => {
  234. name: "居心地のいい場所",
  235. table: [
  236. "【奇・1】一瞬、物音が全て途絶えた。",
  237. "【奇・2】視界の端で何かが動いたような気がする。",
  238. "【奇・3】蔦が少し這いこんでいる。(タナトス +1)",
  239. "【奇・4】妙な息苦しさを覚えた。",
  240. "【奇・5】何かが軋む音がした。",
  241. "【奇・6】小さな明かりがあかあかと揺れている。(パトス +1)",
  242. "【偶・1】物陰になにかの気配を感じた。",
  243. "【偶・2】窓が急に音を立てた。",
  244. "【偶・3】不意に思考がスッキリ晴れてきた。(ロゴス +1)",
  245. "【偶・4】何の前触れもなく、椅子が倒れた。",
  246. "【偶・5】わけもなく寂しい。(エロス +1)",
  247. "【偶・6】軽い眠気に襲われた。",
  248. ]
  249. },
  250. "SKY" => {
  251. name: "空が見える場所",
  252. table: [
  253. "【奇・1】あたたかな風が通り過ぎていく。(パトス +1)",
  254. "【奇・2】光が雲間から漏れているのが見える。",
  255. "【奇・3】ちらほらと、白いものが降り注いでいるように見える。(エロス +1)",
  256. "【奇・4】鳥の鳴き声が聞こえた気がする。",
  257. "【奇・5】雲がものすごいスピードで過ぎ去っていく。",
  258. "【奇・6】どんよりと曇っている。",
  259. "【偶・1】ぽつりと額に冷たいものが落ちてきた。",
  260. "【偶・2】不意に、空に吸い込まれていくような錯覚を覚えた。(ロゴス +1)",
  261. "【偶・3】空は晴れ渡っているようで、頭上に雲は見当たらない。",
  262. "【偶・4】目の前を何かが落ちていった。(タナトス +1)",
  263. "【偶・5】見えるはずの空が、何かに遮られて見えない。",
  264. "【偶・6】空の向こうに、何かが飛んでいくのが見えた。",
  265. ]
  266. },
  267. "BATH" => {
  268. name: "浴室",
  269. table: [
  270. "【奇・1】床のタイルがとても冷たくなっている。",
  271. "【奇・2】バスタブに泡だらけの湯が残っている。",
  272. "【奇・3】床のタイルにひどいひびが入っている。",
  273. "【奇・4】下水の饐えた匂いがする。(ロゴス +1)",
  274. "【奇・5】天井から雫がやけにしたたっている。",
  275. "【奇・6】妙に錆臭いにおいがする。(タナトス +1)",
  276. "【偶・1】【誰かの服(従察)】(コーディネート)がバスタブに投げ込まれ、ぐちゃぐちゃになっている。",
  277. "【偶・2】石鹸のいい匂いがする。(パトス +1)",
  278. "【偶・3】ここしばらく、誰も使った形跡がなく空気が乾いている。",
  279. "【偶・4】シャワーが外れたまま床を這っている。(エロス +1)",
  280. "【偶・5】不健康にじめついていて、どこもかしこもカビだらけでバッチイ。",
  281. "【偶・6】なにかが這い回ったような跡があった。",
  282. ]
  283. },
  284. "BOTANY" => {
  285. name: "植物がある場所",
  286. table: [
  287. "【奇・1】葉が落ちた蔦が、壁一面にビッシリと這っている。",
  288. "【奇・2】どこからともなく、鮮烈な花の香りが漂ってきた。(エロス +1)",
  289. "【奇・3】手折られた花が捨てられていた。",
  290. "【奇・4】茂った葉が、ざわざわと音を立てて揺れた。",
  291. "【奇・5】虫のようなものが、葉の影にもぐりこんでいった。",
  292. "【奇・6】葉が一枚、ひらりと舞い落ちてきた。(ロゴス +1)",
  293. "【偶・1】何かに蔦が絡みつき、オブジェのようになっている。(タナトス +1)",
  294. "【偶・2】枯れた葉が折り重なっている。",
  295. "【偶・3】全くツタの生えていない一角がある。",
  296. "【偶・4】緑のなかに、小さな花がひとつだけ咲いている。(パトス +1)",
  297. "【偶・5】でっかくてまるい【木の実(純押)】(グッズ)が転がっている。",
  298. "【偶・6】壁のヒビから芽が顔を出している。",
  299. ]
  300. },
  301. "WAHER" => {
  302. name: "水がある場所",
  303. table: [
  304. "【奇・1】水に何かが浮いている。",
  305. "【奇・2】不吉な色の水溜りから、不吉な匂いがする。",
  306. "【奇・3】規則正しく滴っていた水音が、不意に途絶えた。(ロゴス +1)",
  307. "【奇・4】清冽な空気が一瞬、走り抜けた。",
  308. "【奇・5】こぽりと空気の抜けるくぐもった音がした。(エロス +1)",
  309. "【奇・6】壁一面がべったりと濡れている。",
  310. "【偶・1】水溜りができている。",
  311. "【偶・2】パイプの裂け目が乾ききっている。",
  312. "【偶・3】じめじめとカビ臭く湿った空気が立ち込めている。",
  313. "【偶・4】水に映った自分の顔が、笑ったように見えた。(タナトス +1)",
  314. "【偶・5】上から雫が落ちて、頭に当たった。",
  315. "【偶・6】浅いと思った水溜りに、足首まで浸かった。(パトス +1)",
  316. ]
  317. },
  318. "DIM" => {
  319. name: "薄暗い場所",
  320. table: [
  321. "【奇・1】足元を何か小さい生き物がすり抜けていった。",
  322. "【奇・2】自分の足音が遅れて聞こえる気がする。",
  323. "【奇・3】呼吸する音がやけに大きく聞こえる。(エロス +1)",
  324. "【奇・4】なんかすっごいヤなもん触った。",
  325. "【奇・5】古いホコリの臭いがする。",
  326. "【奇・6】段々目が慣れてきた",
  327. "【偶・1】視線を感じるような気がする。",
  328. "【偶・2】足元にあった何かをおもいっきり蹴ってしまった。(パトス +1)",
  329. "【偶・3】奥の方に灯りが見える気がする。(タナトス +1)",
  330. "【偶・4】足元の闇に影が落ちた。",
  331. "【偶・5】通路だと思ったら大きな黒いシミのある壁だった。",
  332. "【偶・6】大声で歌い出したい気分だ。(ロゴス +1)",
  333. ]
  334. },
  335. "FIRE" => {
  336. name: "火がある場所",
  337. table: [
  338. "【奇・1】ぱちり、と火の粉が爆ぜた。",
  339. "【奇・2】あったけー。(パトス +1)",
  340. "【奇・3】炎の色が一箇所だけ緑色がかっている。(ロゴス +1)",
  341. "【奇・4】蓋つきの鍋が置いてある。",
  342. "【奇・5】炎の灯りがゆらゆらと肌を照らしている。(エロス +1)",
  343. "【奇・6】食事の残り香とぬくもりを感じた。",
  344. "【偶・1】火が消えかけている。",
  345. "【偶・2】むしろちょっと暑苦しい。",
  346. "【偶・3】洗ってない食器が無造作に積んである。",
  347. "【偶・4】一瞬だけ炎の勢いが増した。(タナトス +1)",
  348. "【偶・5】火にかけられた鍋から不穏な気配がする。",
  349. "【偶・6】火はほっといてもしばらく消えなさそうだ。(パトス +1)",
  350. ]
  351. },
  352. "LABO" => {
  353. name: "ラボトラリー",
  354. table: [
  355. "【奇・1】資料らしき紙束が雑多に積み重なっている。(パトス +1)",
  356. "【奇・2】実験道具が規則正しい音をたてている。",
  357. "【奇・3】ボードに計算式が整然と描き並べられている。(ロゴス +1)",
  358. "【奇・4】薬品臭に甘ったるく苦い匂いが混じっている。(エロス +1)",
  359. "【奇・5】何に使うのか考えたくない系の道具がある。",
  360. "【奇・6】針のない注射器が転がっている。",
  361. "【偶・1】天井が一部剥がされ、基板のようなものがむき出しになっている。",
  362. "【偶・2】散乱する紙やら器具やらに、つまづきかけ",
  363. "【偶・3】工具箱から【工具(打察)】(ツール)がもれている。",
  364. "【偶・4】鳥のような形の模型の、翼が片方折られている。(タナトス +1)",
  365. "【偶・5】哲学的な名言が壁に貼り付けられている。(ロゴス +1)",
  366. "【偶・6】配線が壁から伸びている。",
  367. ]
  368. },
  369. "BED" => {
  370. name: "寝室",
  371. table: [
  372. "【奇・1】やっぱりおふとんは最高だぜ!(パトス +1)",
  373. "【奇・2】ぽっかりとめくれた掛け布団に誘われてる気がする。",
  374. "【奇・3】ゴミ箱がいっぱいになっている。",
  375. "【奇・4】寝床のすみに蔦が手を伸ばしている。(タナトス +1)",
  376. "【奇・5】なんとなく薄ら寒く、ひときわ人肌が恋しい。(エロス +1)",
  377. "【奇・6】シーツがぐしゃぐしゃに乱れている。",
  378. "【偶・1】見覚えのない靴下が落ちている。",
  379. "【偶・2】枕元のあかりが風もないのに揺らいだ。",
  380. "【偶・3】誰かの残り香がするような、しないような。(エロス +1)",
  381. "【偶・4】洋服が脱ぎ散らかされている。",
  382. "【偶・5】薄暗い室内にドアから少し灯りが差し込んでいる。",
  383. "【偶・6】天井のシミが顔のように見える。(ロゴス +1)",
  384. ]
  385. },
  386. "CHIMNEY" => {
  387. name: "煙突街",
  388. table: [
  389. "【奇・1】煙突のひとつが、真っ黒な煙をあげて荒ぶっている。(タナトス +1)",
  390. "【奇・2】煙突の上で動いていた影のようなものが、落ちた気がする。",
  391. "【奇・3】煙突が同じ角度で煙を吐き出している。",
  392. "【奇・4】煙突の煙がオレンジ色に染まっている。(エロス +1)",
  393. "【奇・5】煙突からすすが落ちてきて、服についた。",
  394. "【奇・6】煙突掃除夫が何人か笑い合いながら走っていった。(パトス +1)",
  395. "【偶・1】煙突掃除用のブラシが上から落ちてきた。",
  396. "【偶・2】煙突からすすが落ちてきて、目に入った。",
  397. "【偶・3】煙突掃除夫たちが今日の夜ご飯の算段をしている。",
  398. "【偶・4】煙突の煙が一瞬だけぱったり止まった。",
  399. "【偶・5】煙突が屋根と屋根の隙間からこちらを見下ろしている。(ロゴス +1)",
  400. "【偶・6】煙突のてっぺんに向かうはしごが錆びて朽ちかけている。",
  401. ]
  402. },
  403. "LIBRARY" => {
  404. name: "ライブラリー",
  405. table: [
  406. "【奇・1】破り取られた本の頁が一葉、無残な破れ目をさらしている。",
  407. "【奇・2】静寂の中で本をめくる音がやけに大きく響いた。",
  408. "【奇・3】全集の一冊が欠けている。",
  409. "【奇・4】【気になる本(純押)】(グッズ)があるんだけど、手は届かないしすごい重そう。",
  410. "【奇・5】本の隙間からなにかの気配を感じた気がする。(エロス +1)",
  411. "【奇・6】【広げっぱなしの本(従押)】(グッズ)にひどい落書きがされている。",
  412. "【偶・1】古い本の匂いがする。",
  413. "【偶・2】インクが乾いた【インク瓶(従察)】(グッズ)と【万年筆(打察)】(グッズ)が転がっている。",
  414. "【偶・3】【ブックマーカー(従押)】(グッズ)が一枚落ちている。(パトス +1)",
  415. "【偶・4】誰も居ないはずの背後で、大きな音を立てて本の山が崩れた。(タナトス +1)",
  416. "【偶・5】誰かが議論している声が聞こえてくる。(ロゴス +1)",
  417. "【偶・6】壊れた本が打ち捨てられている。",
  418. ]
  419. },
  420. "SLUM" => {
  421. name: "スラム",
  422. table: [
  423. "【奇・1】口笛を吹かれた。(エロス +1)",
  424. "【奇・2】下品な笑い声が響き渡っている。",
  425. "【奇・3】通りすがりの奴に肩がぶつかりそうになった。",
  426. "【奇・4】誰かに見られているような気がする。",
  427. "【奇・5】壊れた道具が打ち捨てられている。(ロゴス +1)",
  428. "【奇・6】誰かの呻き声が聞こえたような気がする。",
  429. "【偶・1】足跡に唾を吐かれた。",
  430. "【偶・2】何かが打ち付けられたような鈍い音がした。(タナトス +1)",
  431. "【偶・3】扉の壊れた建物から、灯りと怒鳴り声が漏れている。(パトス +1)",
  432. "【偶・4】野良犬がゴミ箱を夢中であさっている。",
  433. "【偶・5】視線に付け回されている気がする。",
  434. "【偶・6】汚物が溜まっている。",
  435. ]
  436. },
  437. "JUNKYARD" => {
  438. name: "ジャンクヤード",
  439. table: [
  440. "【奇・1】頭のとれたネジ巻き式の【からくり人形(従押)】(グッズ)が落ちてる。",
  441. "【奇・2】なんだかとてつもなく嫌な感触のものを踏みつけてしまった。(パトス +1)",
  442. "【奇・3】黒ずんだしみがべっとりついた【袋(支察)】(グッズ)が捨てられている。",
  443. "【奇・4】【何かのパーツ(打察)】(グッズ)が転がっている。",
  444. "【奇・5】このへん、なんか生臭い。",
  445. "【奇・6】大量の【空き缶(純察)】(グッズ)が無駄に丁寧に積んである。",
  446. "【偶・1】誰かに呼ばれたような気がした。(エロス +1)",
  447. "【偶・2】小さなものの影が視界の端を横切った。",
  448. "【偶・3】人間の腕のようなものがゴミの山のなかに見えた気がする。",
  449. "【偶・4】【ちょっといい感じの支持棒(支押)】(グッズ)がゴミ山のてっぺんに刺さっている。",
  450. "【偶・5】何かがガラクタの山のなかで点滅したような気がする。(ロゴス +1)",
  451. "【偶・6】針の無い大きな時計が、物悲しげに鎮座している。(タナトス +1)",
  452. ]
  453. },
  454. "IROMACHI" => {
  455. name: "イロマチ",
  456. table: [
  457. "【奇・1】物憂げな楽の音が聞こえてくる。",
  458. "【奇・2】賑やかな通りの片隅に、ぽっかりと口をあけるように暗い路地が見える。(タナトス +1)",
  459. "【奇・3】楽しげな談笑と歌声が聞こえてくる。(パトス +1)",
  460. "【奇・4】灯が一か所だけ、消えかかっている。",
  461. "【奇・5】【大きな蛾(打押)】(コンパニオン)が灯りの周りを飛び回っている。",
  462. "【奇・6】苦さを含んだ甘ったるい香りが、どこからともなく漂ってくる。(エロス +1)",
  463. "【偶・1】連なる灯りが、一瞬霞んで見えた。",
  464. "【偶・2】据えた酷い匂いに取り巻かれた。",
  465. "【偶・3】品定めするような視線を感じた気がする。(ロゴス +1)",
  466. "【偶・4】踏みつけられてぐしゃぐしゃになった花が一輪落ちている。",
  467. "【偶・5】客引きに無視された。",
  468. "【偶・6】ふと、賑やかな雑踏のなかに取り残されたような感覚に陥った。",
  469. ]
  470. },
  471. "MONASTERY" => {
  472. name: "修道院",
  473. table: [
  474. "【奇・1】水鏡が静かに景色を映している。",
  475. "【奇・2】足音が響いた。",
  476. "【奇・3】階段の踊り場の先から、灯りが近づいてくる。",
  477. "【奇・4】清浄な空気がピンと張り詰めている。(ロゴス +1)",
  478. "【奇・5】薄く開いた扉の向こうから、許しを請う祈りの声が聞こえた気がする。",
  479. "【奇・6】窓が大きく開け放たれて、カーテンが揺れている。(タナトス +1)",
  480. "【偶・1】どこかから囁き合う声が聞こえた気がした。",
  481. "【偶・2】何か重い物が落ちたような音がした。",
  482. "【偶・3】水が跳ねた音がした。",
  483. "【偶・4】誰かの密やかな想いが、壁のすみに刻まれているのを見つけた。(パトス +1)",
  484. "【偶・5】誰かの忘れ物(グッズ APT 純従)が、窓枠の上に置いてある。",
  485. "【偶・6】ステンドグラスが床にうっすらと模様を映している。(エロス +1)",
  486. ]
  487. },
  488. "ROSE" => {
  489. name: "ローズガーデン",
  490. table: [
  491. "【奇・1】滴るような赤い色の薔薇が咲き乱れている。",
  492. "【奇・2】土とは違うものを踏んだ。(ロゴス +1)",
  493. "【奇・3】鐘の音が聞こえた。(タナトス +1)",
  494. "【奇・4】真っ赤な花びらが風に舞っている。",
  495. "【奇・5】すすり泣くような、かすかな歌声がどこからか聞こえた気がする。",
  496. "【奇・6】真新しい墓標に供えられた花束が、音も立てずに揺れている。",
  497. "【偶・1】象牙色の何かが、墓標の足元から覗いている。",
  498. "【偶・2】水の枯れた噴水に、薔薇の蔓が絡み付いている。",
  499. "【偶・3】墓標に足をとられて転びそうになった。",
  500. "【偶・4】故意に叩き壊されたように半分崩れ落ちた墓標がある。(パトス +1)",
  501. "【偶・5】薔薇の香りがやけに鼻につく。(エロス +1)",
  502. "【偶・6】何かの気配を背後に感じた。",
  503. ]
  504. }
  505. }.freeze
  506. 1 register_prefix(EVENT_TABLES.keys)
  507. end
  508. end
  509. end

lib/bcdice/game_system/InfiniteFantasia.rb

100.0% lines covered

94.44% branches covered

29 relevant lines. 29 lines covered and 0 lines missed.
18 total branches, 17 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class InfiniteFantasia < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'InfiniteFantasia'
  7. # ゲームシステム名
  8. 1 NAME = '無限のファンタジア'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'むけんのふあんたしあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. 1D20に目標値を設定した場合に、成功レベルの自動判定を行います。
  14. 例: 1D20<=16
  15. INFO_MESSAGE_TEXT
  16. # ゲーム別成功度判定(1d20)
  17. 1 def result_1d20(total, _dice_total, cmp_op, target)
  18. 14 then: 1 else: 13 return Result.nothing if target == '?'
  19. 13 else: 13 then: 0 return nil unless cmp_op == :<=
  20. 13 then: 1 else: 12 if total > target
  21. 1 return Result.failure("失敗")
  22. end
  23. output =
  24. 12 then: 1 if total <= (target / 32)
  25. 1 else: 11 "32レベル成功(32Lv+)"
  26. 11 then: 2 elsif total <= (target / 16)
  27. 2 else: 9 "16レベル成功(16Lv+)"
  28. 9 then: 3 elsif total <= (target / 8)
  29. 3 else: 6 "8レベル成功"
  30. 6 then: 2 elsif total <= (target / 4)
  31. 2 else: 4 "4レベル成功"
  32. 4 then: 2 elsif total <= (target / 2)
  33. 2 "2レベル成功"
  34. else: 2 else
  35. 2 "1レベル成功"
  36. end
  37. 12 Result.new.tap do |r|
  38. 12 r.text = output
  39. 12 r.success = true
  40. 12 then: 2 else: 10 if total <= 1
  41. 2 r.critical = true
  42. 2 r.text += "/クリティカル"
  43. end
  44. end
  45. end
  46. end
  47. end
  48. end

lib/bcdice/game_system/Insane.rb

100.0% lines covered

88.24% branches covered

61 relevant lines. 61 lines covered and 0 lines missed.
17 total branches, 15 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Insane < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Insane'
  7. # ゲームシステム名
  8. 1 NAME = 'インセイン'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'いんせいん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定(スペシャル/ファンブル/成功/失敗を判定)
  14. ・各種表
  15. シーン表 ST
  16.  本当は怖い現代日本シーン表 HJST/狂騒の二〇年代シーン表 MTST
  17.  暗黒のヴィクトリアシーン表 DVST
  18. 形容表 DT/本体表 BT/部位表 PT
  19. 感情表      FT
  20. 職業表      JT
  21. バッドエンド表  BET
  22. ランダム分野表  RCT
  23. ランダム特技表  RTTn(n:分野番号、省略可能)
  24. 1暴力(TVT)、2情動(TET)、3知覚(TPT)
  25. 4技術(TST)、5知識(TKT)、6怪異(TMT)
  26. ホラースケープ表
  27. 会話(CHT) /街中(VHT)  /不意訪問(IHT)
  28. 廃墟遭遇(RHT)/野外遭遇(MHT)/情報潜在(LHT)
  29. 遭遇表 都市(ECT)/山林(EMT)/海辺(EAT)/反応表 RET
  30. 残業ホラースケープ表(OHT)  /残業電話表(OPT)/残業シーン表(OWT)
  31. 社名決定表1(CNT1)/社名決定表2(CNT2)/社名決定表3(CNT3)
  32. 暫定整理番号作成表(IRN)
  33. ・D66ダイスあり
  34. INFO_MESSAGE_TEXT
  35. 1 def initialize(command)
  36. 120 super(command)
  37. 120 @sort_add_dice = true
  38. 120 @sort_barabara_dice = true
  39. 120 @d66_sort_type = D66SortType::ASC
  40. end
  41. # ゲーム別成功度判定(2D6)
  42. 1 def result_2d6(total, dice_total, _dice_list, cmp_op, target)
  43. 12 else: 12 then: 0 return nil unless cmp_op == :>=
  44. 12 then: 3 if dice_total <= 2
  45. 3 else: 9 Result.fumble(translate("Insane.fumble"))
  46. 9 then: 3 elsif dice_total >= 12
  47. 3 else: 6 Result.critical(translate("Insane.special"))
  48. 6 then: 2 elsif target == "?"
  49. 2 else: 4 Result.nothing
  50. 4 then: 2 elsif total >= target
  51. 2 Result.success(translate("success"))
  52. else: 2 else
  53. 2 Result.failure(translate("failure"))
  54. end
  55. end
  56. 1 def eval_game_system_specific_command(command)
  57. 108 case command
  58. when: 6 when 'BET'
  59. 6 type = translate("Insane.BET.name")
  60. 6 output, total_n = get_badend_table
  61. when: 2 when 'IRN'
  62. 2 type = translate("Insane.IRN.name")
  63. 2 output, total_n = get_interim_reference_number
  64. else: 100 else
  65. 100 return self.class::RTT.roll_command(@randomizer, command) || roll_tables(command, self.class::TABLES)
  66. end
  67. 8 return "#{type}(#{total_n}) > #{output}"
  68. end
  69. 1 private
  70. # バッドエンド表
  71. 1 def get_badend_table
  72. table = [
  73. 6 translate("Insane.BET.items.2"),
  74. 1 lambda { return translate("Insane.BET.items.3", skill: self.class::RTT.roll_skill(@randomizer)) },
  75. translate("Insane.BET.items.4"),
  76. translate("Insane.BET.items.5"),
  77. translate("Insane.BET.items.6"),
  78. translate("Insane.BET.items.7"),
  79. translate("Insane.BET.items.8"),
  80. translate("Insane.BET.items.9"),
  81. translate("Insane.BET.items.10"),
  82. 1 lambda { return translate("Insane.BET.items.11", skill: self.class::RTT.roll_skill(@randomizer)) },
  83. translate("Insane.BET.items.12"),
  84. ]
  85. 6 return get_table_by_2d6(table)
  86. end
  87. # 暫定整理番号作成表
  88. 1 def get_interim_reference_number
  89. table = [
  90. 2 [11, '1'],
  91. [12, '2'],
  92. [13, '3'],
  93. [14, '4'],
  94. [15, '5'],
  95. [16, '6'],
  96. [22, 'G'],
  97. [23, 'I'],
  98. [24, 'J'],
  99. [25, 'K'],
  100. [26, 'O'],
  101. [33, 'P'],
  102. [34, 'Q'],
  103. [35, 'S'],
  104. [36, 'T'],
  105. [44, 'U'],
  106. [45, 'V'],
  107. [46, 'X'],
  108. [55, 'Y'],
  109. [56, 'Z'],
  110. [66, '-'],
  111. ]
  112. 2 number = @randomizer.roll_once(6)
  113. 2 total_n = number.to_s
  114. 2 counts = 3
  115. 2 then: 1 if number <= 4
  116. 1 else: 1 counts = number + 5
  117. 1 then: 1 else: 0 elsif number == 5
  118. 1 counts = 4
  119. end
  120. 2 output = ''
  121. 2 counts.times do
  122. 13 character, number = get_table_by_d66_swap(table)
  123. 13 output += character
  124. 13 total_n += ",#{number}"
  125. end
  126. 2 return output, total_n
  127. end
  128. 1 class << self
  129. 1 private
  130. 1 def translate_tables(locale)
  131. {
  132. 2 "ST" => DiceTable::Table.from_i18n("Insane.table.ST", locale),
  133. "HJST" => DiceTable::Table.from_i18n("Insane.table.HJST", locale),
  134. "MTST" => DiceTable::Table.from_i18n("Insane.table.MTST", locale),
  135. "DVST" => DiceTable::Table.from_i18n("Insane.table.DVST", locale),
  136. "DT" => DiceTable::D66Table.from_i18n("Insane.table.DT", locale),
  137. "BT" => DiceTable::D66Table.from_i18n("Insane.table.BT", locale),
  138. "PT" => DiceTable::D66Table.from_i18n("Insane.table.PT", locale),
  139. "FT" => DiceTable::Table.from_i18n("Insane.table.FT", locale),
  140. "JT" => DiceTable::D66Table.from_i18n("Insane.table.JT", locale),
  141. "CHT" => DiceTable::Table.from_i18n("Insane.table.CHT", locale),
  142. "VHT" => DiceTable::Table.from_i18n("Insane.table.VHT", locale),
  143. "IHT" => DiceTable::Table.from_i18n("Insane.table.IHT", locale),
  144. "RHT" => DiceTable::Table.from_i18n("Insane.table.RHT", locale),
  145. "MHT" => DiceTable::Table.from_i18n("Insane.table.MHT", locale),
  146. "LHT" => DiceTable::Table.from_i18n("Insane.table.LHT", locale),
  147. "ECT" => DiceTable::Table.from_i18n("Insane.table.ECT", locale),
  148. "EMT" => DiceTable::Table.from_i18n("Insane.table.EMT", locale),
  149. "EAT" => DiceTable::Table.from_i18n("Insane.table.EAT", locale),
  150. "OHT" => DiceTable::Table.from_i18n("Insane.table.OHT", locale),
  151. "OPT" => DiceTable::Table.from_i18n("Insane.table.OPT", locale),
  152. "OWT" => DiceTable::Table.from_i18n("Insane.table.OWT", locale),
  153. "CNT1" => DiceTable::Table.from_i18n("Insane.table.CNT1", locale),
  154. "CNT2" => DiceTable::Table.from_i18n("Insane.table.CNT2", locale),
  155. "CNT3" => DiceTable::Table.from_i18n("Insane.table.CNT3", locale),
  156. "RET" => DiceTable::Table.from_i18n("Insane.table.RET", locale),
  157. }
  158. end
  159. 1 def translate_rtt(locale)
  160. 2 DiceTable::SaiFicSkillTable.from_i18n("Insane.RTT", locale, rttn: ["TVT", "TET", "TPT", "TST", "TKT", "TMT"])
  161. end
  162. end
  163. 1 TABLES = translate_tables(:ja_jp)
  164. 1 RTT = translate_rtt(:ja_jp)
  165. 1 register_prefix("BET", "IRN", RTT.prefixes, TABLES.keys)
  166. end
  167. end
  168. end

lib/bcdice/game_system/Insane_Korean.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/Insane"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Insane_Korean < Insane
  6. # ゲームシステムの識別子
  7. 1 ID = 'Insane:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '인세인'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:인세인'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・판정
  15. 스페셜/펌블/성공/실패를 판정
  16. ・각종표
  17. 장면표   ST
  18.  사실은 무서운 현대 일본 장면표 HJST/광란의 20년대 장면표 MTST
  19.  빅토리아의 어둠 장면표 DVST
  20. 형용표    DT
  21.  본체표 BT/부위표 PT
  22. 감정표      FT
  23. 직업표      JT
  24. 배드엔드표  BET
  25. 랜덤 특기 결정표 RTT
  26. 지정특기(폭력)표  (TVT)
  27. 지정특기(정서)표  (TET)
  28. 지정특기(지각)표  (TPT)
  29. 지정특기(기술)표  (TST)
  30. 지정특기(지식)표  (TKT)
  31. 지정특기(괴이)표  (TMT)
  32. 회화 중에 생겨나는 공포표(CHT)
  33. 거리에서 마주치는 공포표(VHT)
  34. 갑자기 찾아오는 공포표(IHT)
  35. 폐허에서 마주치는 공포표(RHT)
  36. 야외에서 마주치는 공포표(MHT)
  37. 정보 속에 숨어있는 공포표(LHT)
  38. 조우표 도시 (ECT) 산림 (EMT) 해변 (EAT)/반응표 RET
  39. 야근 호러 스케이프 OHT/야근 전화표 OPT/야근 장면표 OWT
  40. 회사명 결정표1 CNT1/회사명 결정표2 CNT2/회사명 결정표3 CNT3
  41. ・D66 다이스 있음.
  42. INFO_MESSAGE_TEXT
  43. 1 register_prefix_from_super_class()
  44. 1 def initialize(command)
  45. 57 super(command)
  46. 57 @locale = :ko_kr
  47. end
  48. 1 TABLES = translate_tables(:ko_kr)
  49. 1 RTT = translate_rtt(:ko_kr)
  50. end
  51. end
  52. end

lib/bcdice/game_system/InvisibleLiar.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class InvisibleLiar < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'InvisibleLiar'
  7. # ゲームシステム名
  8. 1 NAME = 'インビジブルライアー'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'いんひしふるらいああ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~HELP
  13. ■ 採取表
  14. WOODSn 森
  15. PRAIRIEn 草原
  16. LAKEn 湖
  17. RIVERn 川辺
  18. SWAMPn 沼地
  19. CAVEn 洞窟
  20. ROCKYn 岩場
  21. MOUNTAINn 山岳
  22. n: 採取時間(1〜5)
  23. HELP
  24. 1 def eval_game_system_specific_command(command)
  25. 41 roll_tables(command, TABLES)
  26. end
  27. TABLES = {
  28. 1 "WOODS1" => DiceTable::Table.new("森 1時間", "1D6", ["麗し草", "麗し草", "麗し草", "神秘のキノコ", "妖精の羽", "成果なし"]),
  29. "WOODS2" => DiceTable::Table.new("森 2時間", "1D6", ["麗し草", "麗し草", "神秘のキノコ", "神秘のキノコ", "妖精の羽", "成果なし"]),
  30. "WOODS3" => DiceTable::Table.new("森 3時間", "1D6", ["麗し草", "神秘のキノコ", "神秘のキノコ", "神秘のキノコ", "妖精の羽", "成果なし"]),
  31. "WOODS4" => DiceTable::Table.new("森 4時間", "1D6", ["麗し草", "神秘のキノコ", "神秘のキノコ", "妖精の羽", "妖精の羽", "成果なし"]),
  32. "WOODS5" => DiceTable::Table.new("森 5時間", "1D6", ["麗し草", "神秘のキノコ", "妖精の羽", "妖精の羽", "妖精の羽", "成果なし"]),
  33. "PRAIRIE1" => DiceTable::Table.new("草原 1時間", "1D6", ["太陽の花", "太陽の花", "太陽の花", "生命の虫", "妖精の羽", "成果なし"]),
  34. "PRAIRIE2" => DiceTable::Table.new("草原 2時間", "1D6", ["太陽の花", "太陽の花", "生命の虫", "生命の虫", "妖精の羽", "成果なし"]),
  35. "PRAIRIE3" => DiceTable::Table.new("草原 3時間", "1D6", ["太陽の花", "生命の虫", "生命の虫", "生命の虫", "妖精の羽", "成果なし"]),
  36. "PRAIRIE4" => DiceTable::Table.new("草原 4時間", "1D6", ["太陽の花", "生命の虫", "生命の虫", "妖精の羽", "妖精の羽", "成果なし"]),
  37. "PRAIRIE5" => DiceTable::Table.new("草原 5時間", "1D6", ["太陽の花", "生命の虫", "妖精の羽", "妖精の羽", "妖精の羽", "成果なし"]),
  38. "LAKE1" => DiceTable::Table.new("湖 1時間", "1D6", ["竜の鱗", "竜の鱗", "竜の鱗", "マンドレイク", "幻獣の涙", "成果なし"]),
  39. "LAKE2" => DiceTable::Table.new("湖 2時間", "1D6", ["竜の鱗", "竜の鱗", "マンドレイク", "マンドレイク", "幻獣の涙", "成果なし"]),
  40. "LAKE3" => DiceTable::Table.new("湖 3時間", "1D6", ["竜の鱗", "マンドレイク", "マンドレイク", "マンドレイク", "幻獣の涙", "成果なし"]),
  41. "LAKE4" => DiceTable::Table.new("湖 4時間", "1D6", ["竜の鱗", "マンドレイク", "マンドレイク", "幻獣の涙", "幻獣の涙", "成果なし"]),
  42. "LAKE5" => DiceTable::Table.new("湖 5時間", "1D6", ["竜の鱗", "マンドレイク", "幻獣の涙", "幻獣の涙", "幻獣の涙", "成果なし"]),
  43. "RIVER1" => DiceTable::Table.new("川辺 1時間", "1D6", ["魔魚", "魔魚", "魔魚", "麗し草", "幻獣の涙", "成果なし"]),
  44. "RIVER2" => DiceTable::Table.new("川辺 2時間", "1D6", ["魔魚", "魔魚", "麗し草", "麗し草", "幻獣の涙", "成果なし"]),
  45. "RIVER3" => DiceTable::Table.new("川辺 3時間", "1D6", ["魔魚", "麗し草", "麗し草", "麗し草", "幻獣の涙", "成果なし"]),
  46. "RIVER4" => DiceTable::Table.new("川辺 4時間", "1D6", ["魔魚", "麗し草", "麗し草", "幻獣の涙", "幻獣の涙", "成果なし"]),
  47. "RIVER5" => DiceTable::Table.new("川辺 5時間", "1D6", ["魔魚", "麗し草", "幻獣の涙", "幻獣の涙", "幻獣の涙", "成果なし"]),
  48. "SWAMP1" => DiceTable::Table.new("沼地 1時間", "1D6", ["マンドレイク", "マンドレイク", "マンドレイク", "魔魚", "畏怖の化石", "成果なし"]),
  49. "SWAMP2" => DiceTable::Table.new("沼地 2時間", "1D6", ["マンドレイク", "マンドレイク", "魔魚", "魔魚", "畏怖の化石", "成果なし"]),
  50. "SWAMP3" => DiceTable::Table.new("沼地 3時間", "1D6", ["マンドレイク", "魔魚", "魔魚", "魔魚", "畏怖の化石", "成果なし"]),
  51. "SWAMP4" => DiceTable::Table.new("沼地 4時間", "1D6", ["マンドレイク", "魔魚", "魔魚", "畏怖の化石", "畏怖の化石", "成果なし"]),
  52. "SWAMP5" => DiceTable::Table.new("沼地 5時間", "1D6", ["マンドレイク", "魔魚", "畏怖の化石", "畏怖の化石", "畏怖の化石", "成果なし"]),
  53. "CAVE1" => DiceTable::Table.new("洞窟 1時間", "1D6", ["神秘のキノコ", "神秘のキノコ", "神秘のキノコ", "魔素の結晶", "畏怖の化石", "成果なし"]),
  54. "CAVE2" => DiceTable::Table.new("洞窟 2時間", "1D6", ["神秘のキノコ", "神秘のキノコ", "魔素の結晶", "魔素の結晶", "畏怖の化石", "成果なし"]),
  55. "CAVE3" => DiceTable::Table.new("洞窟 3時間", "1D6", ["神秘のキノコ", "魔素の結晶", "魔素の結晶", "魔素の結晶", "畏怖の化石", "成果なし"]),
  56. "CAVE4" => DiceTable::Table.new("洞窟 4時間", "1D6", ["神秘のキノコ", "魔素の結晶", "魔素の結晶", "畏怖の化石", "畏怖の化石", "成果なし"]),
  57. "CAVE5" => DiceTable::Table.new("洞窟 5時間", "1D6", ["神秘のキノコ", "魔素の結晶", "畏怖の化石", "畏怖の化石", "畏怖の化石", "成果なし"]),
  58. "ROCKY1" => DiceTable::Table.new("岩場 1時間", "1D6", ["生命の虫", "生命の虫", "生命の虫", "竜の鱗", "星の欠片", "成果なし"]),
  59. "ROCKY2" => DiceTable::Table.new("岩場 2時間", "1D6", ["生命の虫", "生命の虫", "竜の鱗", "竜の鱗", "星の欠片", "成果なし"]),
  60. "ROCKY3" => DiceTable::Table.new("岩場 3時間", "1D6", ["生命の虫", "竜の鱗", "竜の鱗", "竜の鱗", "星の欠片", "成果なし"]),
  61. "ROCKY4" => DiceTable::Table.new("岩場 4時間", "1D6", ["生命の虫", "竜の鱗", "竜の鱗", "星の欠片", "星の欠片", "成果なし"]),
  62. "ROCKY5" => DiceTable::Table.new("岩場 5時間", "1D6", ["生命の虫", "竜の鱗", "星の欠片", "星の欠片", "星の欠片", "成果なし"]),
  63. "MOUNTAIN1" => DiceTable::Table.new("山岳 1時間", "1D6", ["魔素の結晶", "魔素の結晶", "魔素の結晶", "太陽の花", "星の欠片", "成果なし"]),
  64. "MOUNTAIN2" => DiceTable::Table.new("山岳 2時間", "1D6", ["魔素の結晶", "魔素の結晶", "太陽の花", "太陽の花", "星の欠片", "成果なし"]),
  65. "MOUNTAIN3" => DiceTable::Table.new("山岳 3時間", "1D6", ["魔素の結晶", "太陽の花", "太陽の花", "太陽の花", "星の欠片", "成果なし"]),
  66. "MOUNTAIN4" => DiceTable::Table.new("山岳 4時間", "1D6", ["魔素の結晶", "太陽の花", "太陽の花", "星の欠片", "星の欠片", "成果なし"]),
  67. "MOUNTAIN5" => DiceTable::Table.new("山岳 5時間", "1D6", ["魔素の結晶", "太陽の花", "星の欠片", "星の欠片", "星の欠片", "成果なし"]),
  68. }.freeze
  69. 1 register_prefix(TABLES.keys)
  70. end
  71. end
  72. end

lib/bcdice/game_system/Irisbane.rb

100.0% lines covered

96.0% branches covered

60 relevant lines. 60 lines covered and 0 lines missed.
25 total branches, 24 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Irisbane < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Irisbane'
  7. # ゲームシステム名
  8. 1 NAME = '瞳逸らさぬイリスベイン'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ひとみそらさぬいりすへいん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~HELP
  13. ■攻撃判定( ATTACKx@y<=z )
  14. x: 攻撃力
  15. y: 判定数
  16. z: 目標値
  17. (※ ATTACK は ATK または AT と簡略化可能)
  18. 例) ATTACK2@3<=5
  19. 例) ATK10@2<=4
  20. 例) AT8@3<=2
  21. 上記 x y z にはそれぞれ四則演算を指定可能。
  22. 例) ATTACK2+7@3*2<=5-1
  23. □攻撃判定のダメージ増減( ATTACKx@y<=z[+a] ATTACKx@y<=z[-a])
  24. 末尾に [+a] または [-a] と指定すると、最終的なダメージを増減できる。
  25. a: 増減量
  26. 例) ATTACK2@3<=5[+10]
  27. 例) ATK10@2<=4[-8]
  28. 例) AT8@3<=2[-8+5]
  29. ■シチュエーション(p115)
  30. SceneSituation, SSi
  31. HELP
  32. 1 ATTACK_ROLL_REG = %r{^AT(TACK|K)?([+\-*/()\d]+)@([+\-*/()\d]+)<=([+\-*/()\d]+)(\[([+-])([+\-*/()\d]+)\])?}i.freeze
  33. 1 register_prefix('AT(TACK|K)?')
  34. 1 def initialize(command)
  35. 41 super(command)
  36. 41 @sort_barabara_dice = true
  37. 41 @round_type = RoundType::CEIL
  38. end
  39. 1 def eval_game_system_specific_command(command)
  40. 39 command = ALIAS[command] || command
  41. 39 then: 35 if (m = ATTACK_ROLL_REG.match(command))
  42. 35 roll_attack(m[2], m[3], m[4], m[6], m[7])
  43. else: 4 else
  44. 4 roll_tables(command, TABLES)
  45. end
  46. end
  47. 1 private
  48. 1 def roll_attack(power_expression, dice_count_expression, border_expression, modification_operator, modification_expression)
  49. 35 power = Arithmetic.eval(power_expression, RoundType::CEIL)
  50. 35 dice_count = Arithmetic.eval(dice_count_expression, RoundType::CEIL)
  51. 35 border = Arithmetic.eval(border_expression, RoundType::CEIL)
  52. 35 then: 27 else: 8 modification_value = modification_expression.nil? ? nil : Arithmetic.eval(modification_expression, RoundType::CEIL)
  53. 35 then: 4 else: 31 return if power.nil? || dice_count.nil? || border.nil?
  54. 31 then: 1 else: 30 return if modification_operator && modification_value.nil?
  55. 30 then: 1 else: 29 power = 0 if power < 0
  56. 30 border = border.clamp(1, 6)
  57. 30 command = make_command_text(power, dice_count, border, modification_operator, modification_value)
  58. 30 then: 1 else: 29 if dice_count <= 0
  59. 1 return "#{command} > 判定数が 0 です"
  60. end
  61. 29 dices = @randomizer.roll_barabara(dice_count, 6).sort
  62. 160 success_dice_count = dices.count { |dice| dice <= border }
  63. 29 damage = success_dice_count * power
  64. 29 message_elements = []
  65. 29 message_elements << command
  66. 29 message_elements << dices.join(',')
  67. 29 message_elements << "成功ダイス数 #{success_dice_count}"
  68. 29 then: 25 else: 4 message_elements << "× 攻撃力 #{power}" if success_dice_count > 0
  69. 29 then: 25 else: 4 if success_dice_count > 0
  70. 25 then: 6 if modification_operator && modification_value
  71. 6 message_elements << "ダメージ #{damage}#{modification_operator}#{modification_value}"
  72. 6 damage = parse_operator(modification_operator).call(damage, modification_value)
  73. 6 then: 1 else: 5 damage = 0 if damage < 0
  74. 6 message_elements << damage.to_s
  75. else: 19 else
  76. 19 message_elements << "ダメージ #{damage}"
  77. end
  78. end
  79. 29 Result.new(message_elements.join(' > ')).tap do |r|
  80. 29 r.condition = success_dice_count > 0
  81. end
  82. end
  83. 1 def make_command_text(power, dice_count, border, modification_operator, modification_value)
  84. 30 text = "(ATTACK#{power}@#{dice_count}<=#{border}"
  85. 30 then: 7 else: 23 text += "[#{modification_operator}#{modification_value}]" if modification_operator
  86. 30 text += ")"
  87. 30 text
  88. end
  89. 1 def parse_operator(operator)
  90. 6 else: 0 case operator
  91. when: 3 when '+'
  92. 6 lambda { |x, y| x + y }
  93. when: 3 when '-'
  94. 6 lambda { |x, y| x - y }
  95. end
  96. end
  97. TABLES = {
  98. 1 "SceneSituation" => DiceTable::D66LeftRangeTable.new(
  99. "シチュエーション",
  100. BCDice::D66SortType::NO_SORT,
  101. [
  102. [1..3, [
  103. "【日常】何一つ変わることの無い日々の一幕。移ろい易い世界では、それはとても大切である。",
  104. "【準備】何かを為すための用意をする一幕。情報収集、買物遠征、やるべきことは一杯だ。",
  105. "【趣味】自分の時間を、有効活用している一幕。必要に追われていない分、心は軽く晴れやかだ。",
  106. "【喫茶】一息入れ、嗜好品を嗜む時の一幕。穏やかな空気は、だが、往々にして変わりやすい。",
  107. "【鍛錬】体を鍛え、心を養う修練の一幕。己さえ良ければ、その方法も何だって良い。",
  108. "【職務】役割の元、仕事に精を出す時の一幕。目的が何であれ、為すべきことに変わりはない。",
  109. ]],
  110. [4..6, [
  111. "【移動】何処かから何処かへと向かう一幕。進んでいるなら、手段も目的地も関係あるまい。",
  112. "【墓前】故人が眠る場所へと赴く一幕。共に眠ることだけは無いように。",
  113. "【操作】何かを操り、望みを果たしている一幕。運転にせよ何にせよ、脇見には注意が必要だ。",
  114. "【食事】何かを糧とし、己の力を蓄える一幕。行動すれば消耗する。腹が減っては何とやらだ。",
  115. "【休息】日々の合間の、憩いの一幕。“何もしない”というのも、立派な行いである。",
  116. "【夢幻】現実に存在しない何かへと耽る一幕。時間帯に関わらず、何時かは必ず覚めるだろう。",
  117. ]],
  118. ]
  119. ),
  120. }.transform_keys(&:upcase).freeze
  121. 1 ALIAS = {
  122. "SSi" => "SceneSituation",
  123. }.transform_keys(&:upcase).transform_values(&:upcase).freeze
  124. 1 register_prefix(TABLES.keys, ALIAS.keys)
  125. end
  126. end
  127. end

lib/bcdice/game_system/IthaWenUa.rb

93.33% lines covered

87.5% branches covered

15 relevant lines. 14 lines covered and 1 lines missed.
8 total branches, 7 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class IthaWenUa < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'IthaWenUa'
  7. # ゲームシステム名
  8. 1 NAME = 'イサー・ウェン=アー'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'いさあうえんああ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = "1D100<=m 方式の判定で成否、クリティカル(01)・ファンブル(00)を自動判定します。\n"
  13. 1 def result_1d100(total, _dice_total, cmp_op, target)
  14. 9 else: 8 then: 1 return nil unless cmp_op == :<=
  15. 8 then: 3 if total % 100 == 1
  16. 3 else: 5 Result.critical("01 > クリティカル")
  17. 5 then: 2 elsif total % 100 == 0
  18. 2 else: 3 Result.fumble("00 > ファンブル")
  19. 3 then: 0 else: 3 elsif target == "?"
  20. Result.nothing
  21. end
  22. end
  23. end
  24. end
  25. end

lib/bcdice/game_system/JamesBond.rb

100.0% lines covered

92.86% branches covered

22 relevant lines. 22 lines covered and 0 lines missed.
14 total branches, 13 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class JamesBond < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'JamesBond'
  7. # ゲームシステム名
  8. 1 NAME = 'ジェームズ・ボンド007'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'しええむすほんと007'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・1D100の目標値判定で、効果レーティングを1~4で自動判定。
  14.  例)1D100<=50
  15.    JamesBond : (1D100<=50) > 20 > 効果3(良)
  16. INFO_MESSAGE_TEXT
  17. 1 def result_1d100(total, _dice_total, cmp_op, target) # ゲーム別成功度判定(1d100)
  18. 17 then: 1 else: 16 return Result.nothing if target == '?'
  19. 16 else: 16 then: 0 return nil unless cmp_op == :<=
  20. 16 base = ((target + 9) / 10).floor
  21. 16 if total >= 100
  22. then: 1 # 100は常に失敗
  23. 1 else: 15 Result.failure("失敗")
  24. 15 then: 5 elsif total <= base
  25. 5 else: 10 Result.success("効果1(完璧)")
  26. 10 then: 4 elsif total <= base * 2
  27. 4 else: 6 Result.success("効果2(かなり良い)")
  28. 6 then: 2 elsif total <= base * 5
  29. 2 else: 4 Result.success("効果3(良)")
  30. 4 then: 3 elsif total <= target
  31. 3 Result.success("効果4(まあまあ)")
  32. else: 1 else
  33. 1 Result.failure("失敗")
  34. end
  35. end
  36. end
  37. end
  38. end

lib/bcdice/game_system/JekyllAndHyde.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/DesperateRun"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class JekyllAndHyde < DesperateRun
  6. # ゲームシステムの識別子
  7. 1 ID = "JekyllAndHyde"
  8. # ゲームシステム名
  9. 1 NAME = "ジキルとハイドとグリトグラ"
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = "しきるとはいととくりとくら"
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~HELP
  14. ・難易度算出コマンド DDC
  15. ・判定コマンド RCx or RCx+y or RCx-y(x=難易度、y=修正値(省略可能))
  16. ・目標決定表 GOALT
  17. HELP
  18. TABLES = {
  19. 1 "GOALT" => DiceTable::Table.new(
  20. "目標決定表",
  21. "1D6",
  22. [
  23. "「主人格の目的達成」",
  24. "「主人格の目的阻害」",
  25. "「主人格のハッピーエンド(目的達成しなくてもよい)」",
  26. "「主人格のバッドエンド(目的達成していてもよい)」",
  27. "「自分の人格が目的を決定できる」",
  28. "「主人格の目的達成」「主人格の目的阻害」「主人格のハッピーエンド(目的達成しなくてもよい)」「主人格のバッドエンド(目的達成していてもよい)」「自分の人格が目的を決定できる」のどれかを自由に選べる"
  29. ]
  30. )
  31. }.freeze
  32. 1 register_prefix('RC', 'DDC', TABLES.keys)
  33. end
  34. end
  35. end

lib/bcdice/game_system/JuinKansen.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class JuinKansen < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "JuinKansen"
  7. # ゲームシステム名
  8. 1 NAME = "呪印感染"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "しゆいんかんせん"
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ■ 表
  14. ・日常表 (DAI, Daily)
  15. ・場所表
  16. ・「都市」 (PCI, PlaceCity)
  17. ・「田舎」 (PCO, PlaceCountryside)
  18. ・「施設内」 (PFA, PlaceFacility)
  19. ・初見表 (FL, FirstLook)
  20. ・知己表 (AF, AppreciativeFriend)
  21. ・伏線表 (FOR, Foreshadow)
  22. ・感情表 (EMO, Emotion)
  23. ・状況表 (SIT, Situation)
  24. ・対象表 (TAR, Target)
  25. ・狂気表 (INS, Insanity)
  26. ・終焉表 (DEA, Death)
  27. ・恐怖表 (FEA, Fear)
  28. INFO_MESSAGE_TEXT
  29. 1 def eval_game_system_specific_command(command)
  30. 52 roll_tables(ALIAS[command] || command, TABLES)
  31. end
  32. TABLES = {
  33. 1 "Daily" => DiceTable::Table.new(
  34. "日常表",
  35. "2D6",
  36. [
  37. "「入浴中」『内容』PCの自己紹介後、自宅でどのように入浴しているかについて、簡単に説明せよ。『終了条件』GMが「体を洗い終えたので、そろそろあがることにした」と宣言する。",
  38. "「自炊」『内容』PCの自己紹介後、自宅でどんな食事を作るか、自炊が苦手かどうかなどを説明せよ。『終了条件』GMが「料理ができたので、食事を始めた」と宣言する。",
  39. "「休憩時間」『内容』PCの自己紹介後、仕事や学業の休憩時間に、どこで何をしているのか簡単に説明せよ。『終了条件』GMが「そろそろ、休憩時間が終わりそうだ」と宣言する。",
  40. "「帰宅中」『内容』PCの自己紹介後、仕事や学業から帰宅途中、何をしているかを簡単に説明せよ。『終了条件』GMが自宅に到着したと宣言する。",
  41. "「昼休み」『内容』PCの自己紹介後、仕事や学業の昼休み中、どこでなにを食べているのかを簡単に説明せよ。『終了条件』GMが昼休みがそろそろ終わると宣言する。",
  42. "「仕事中」『内容』PCの自己紹介後、仕事や学業に対して、どのような態度で臨んでいるのかを簡単に説明せよ。『終了条件』GMが休憩時間を知らせるチャイムなどが鳴ったと宣言する。",
  43. "「通勤・通学」『内容』PCの自己紹介後、どのような方法で通勤・通学しているかを簡単に説明せよ。『終了条件』GMが職場や学校に到着したと宣言する。",
  44. "「休日」『内容』PCの自己紹介後、休日に何をしているか簡単に説明せよ。『終了条件』GMが「そろそろ、明日に備えなければ」と宣言する。",
  45. "「自宅」『内容』PCの自己紹介後、自宅の自室で、どのようにくつろいでいるかを簡単に説明せよ。『終了条件』GMが「そろそろ、寝る時間のようだ」と宣言する。",
  46. "「寝起き直後」『内容』PCの自己紹介後、自宅で起床直後、どのような行動を取るかについて、簡単に説明せよ。『終了条件』GMが「出勤・通学の準備が整った」と宣言する。",
  47. "「趣味」『内容』PCの自己紹介後、自室でどんな趣味に没頭しているかを簡単に説明せよ。『終了条件』GMが「名残惜しいが、そろそろ寝る時間のようだ」と宣言する。",
  48. ]
  49. ),
  50. "PlaceCity" => DiceTable::Table.new(
  51. "場所表「都市」",
  52. "2D6",
  53. [
  54. "「事件現場」ここは以前、怪事件が起こったと噂される事件現場だ。よく見ると、近くには枯れた花束が置かれている。",
  55. "「帰宅路」ここは帰宅路だ。時間帯のせいか周囲に人気はなく、耳鳴りがするほどの静寂に包まれている。",
  56. "「近所の公園」ここは自宅・会社・学校いずれかの近くにある公園だ。今いる場所は、奥のあずまやで、近くには自販機が並んでいる。",
  57. "「近所のコンビニ」ここはPCの自宅近くにある、コンビニエンスストアだ。大きな駐車場のせいか、周囲は実に広々としている。",
  58. "「飲食店」ここはどこにでもある飲食店だ。しかし、客の入りはまばらで、周囲には空席が目立つ。",
  59. "「駅の広場」ここは人々が通勤や通学に使う駅の広場だ。が、行き交う人々の視線はどこか冷たく、虚ろにさえ見える。",
  60. "「神社仏閣」ここは街のなかにある神社・寺社だ。頼めばお祓いをしてくれるという話だが、ご利益があるかは不明だ。",
  61. "「図書館」ここは街中にある公立の図書館だ。周囲には新旧の様々な書籍が並び、調べものをするにはうってつけだ。",
  62. "「河川敷の道」ここは近所にある河川敷沿いの道だ。周囲に人気はなく、無機質な道路が遠くまで続いてる。",
  63. "「病院の前」ここは近所にある総合病院の前だ。通院患者と思しき老人や若者が、時折、真新しい出入り口を行き来している。",
  64. "「警察署の前」ここは街中にある警察署の前だ。今回の事件、あるいは先ほどの怪現象を話しても……おそらく、信じてはくれないだろう。",
  65. ]
  66. ),
  67. "PlaceCountryside" => DiceTable::Table.new(
  68. "場所表「田舎」",
  69. "2D6",
  70. [
  71. "「事件現場」ここは以前、怪事件が起こったと噂される事件現場だ。よく見ると、近くには枯れた花束が置いてある。",
  72. "「学校の前」ここは村の奥にある学校の前だ。しかし、何年も前に廃校したらしく、門は固く閉ざされ、校庭には雑草が生い茂っている。",
  73. "「公園」ここは村の中にある公園だ。中央にたたずむ遊具はいずれも錆びついており、所々に雑草が生えている。",
  74. "「村役場」ここは村にある役場だ。しかし、役場のドアは締め切られたままで、なかに人の気配はない。",
  75. "「森の中」ここは道路から離れた場所にある森の中だ。周囲からは、動物と思しき鳴き声が聞こえてくる。",
  76. "「バス停」ここは村唯一のバス停だ。時刻表を見てみるが、バスは一日に一本しか通ってないらしい。",
  77. "「神社仏閣」ここは村の中にある神社・寺社だ。境内はさびれており、人の気配は皆無に等しい。",
  78. "「田畑」ここは村の外れにある田畑だ。農閑期のせいか、畑は放置されたままで、周囲を見渡しても人の姿はない。",
  79. "「川辺」ここは村の外れにある川の近くだ。目前の川は透き通っており、何匹も魚が泳いでいる。",
  80. "「病院の前」ここは村にある小さな病院の前だ。しかし、今日は定休日なのか、病院は閉まったままだ。",
  81. "「交番の前」ここは村唯一の交番だ。しかし、警察官の姿はなく、ドアも締め切られたままだ。",
  82. ]
  83. ),
  84. "PlaceFacility" => DiceTable::Table.new(
  85. "場所表「施設内」",
  86. "2D6",
  87. [
  88. "「礼拝堂」ここは地下に存在する、礼拝堂と思しき場所だ。部屋の奥には奇妙な姿をした石像があり、周囲には瘴気が漂っている。",
  89. "「隠し部屋」ここは隠し部屋と思しき場所だ。部屋の壁には、血痕のような汚れが染みついている。",
  90. "「倉庫」ここは中心部に存在する倉庫だ。場所のせいか、はたまた異変のせいか、周囲には不気味なカビが生えている。",
  91. "「寝台」ここは寝台のある場所だ。内部には簡素なベッドと机が置かれているだけで、非常に殺風景だ。",
  92. "「応接室」ここは応接室と思しき場所だ。部屋の中央には、大きめのテーブルとソファが置いてある。",
  93. "「廊下」ここは施設内を通る廊下の1つだ。伝統がついていないせいか、それとも時間帯のせいか、周囲はやけに薄暗い。",
  94. "「ロビー」ここはロビーだ。扉は相変わらず開く気配がなく、周囲は静まり返っている。",
  95. "「踊り場」ここは階段の踊り場だ。周囲は非常に薄暗く、これといって何もない。",
  96. "「地下室」ここは地下室だ。床にはうっすらと埃が積もり、長年使われていないように思える。",
  97. "「実験室」ここは実験室と思しき場所だ。中央には大きなテーブルが設置されており、どういうわけか血まみれだ。",
  98. "「研究室」ここは研究室と思しき場所だ。部屋は全体的に暗く、奥の棚には奇妙な姿をした生物のホルマリン漬けが並んでる。",
  99. ]
  100. ),
  101. "FirstLook" => DiceTable::Table.new(
  102. "初見表",
  103. "2D6",
  104. [
  105. "「襲撃からの救出」『内容』PC同士が再会後、【命運】の低いPCが突如、不良などに絡まれ、【命運】の高いPCが実力や機転で救う場面を演出せよ。『終了条件』【命運】の低いPCが、【命運】の高いPCに対して感謝の言葉を述べる。",
  106. "「落とし物」『内容』PC同士が再会後、【幸運】の低いPCが荷物を落とし、それを【幸運】の高いPCが拾い、手渡す場面を演出せよ。『終了条件』【幸運】の低いPCが【幸運】の高いPCの[呪印]に気付く。",
  107. "「黒い影」『内容』PC同士が再会後、【精神】の高いPCが、【精神】の低いPCの背後に黒い影を目撃する場面を演出せよ。『終了条件』【精神】の高いPCが「さっきの……なに?」と問う。",
  108. "「<なにか>を見た」『内容』PC同士が再会後、【幸運】の低いPCが暗がりの奥で<なにか>を目撃。顔面蒼白となる場面を演出せよ。『終了条件』【幸運】の高いPCが【幸運】の低いPCを気遣う。",
  109. "「呼び声」『内容』PC同士は再会後、遠くから不気味な呼び声を聞き、周囲を見回すうちに、目が合う場面を演出せよ。『終了条件』PCのいずれかが「今の……聞こえた?」と問いかけ、いずれかが返答する。",
  110. "「知り合い」『内容』PC同士が再会後、実は知り合いの知り合いだったことが判明する場面を演出せよ。『終了条件』PC同士がどんな関係かについて相談・決定する。",
  111. "「事故からの救出」『内容』落下物や交通事故など、【希望】の低いPCが突如、不可解な事故に巻き込まれ、【希望】の高いPCに救われる場面を演出せよ。『終了条件』【希望】の低いPCが、【希望】の高いPCに感謝の言葉を述べる。",
  112. "「SNS」『内容』【知性】の高いPCがSNS上で事件に関する発信を行い、【知性】の低いPCと知り合う場面を演出せよ。『終了条件』【知性】の低いPCが「また今度、お会いしましょう」と返信する。",
  113. "「<なにか>が見える」『内容』PC同士が再会後、暗がりの向こうで<なにか>を目撃、戦慄する場面を演出せよ。『終了条件』<なにか>が消え去り、PCのいずれかが「……さっきの見た?」と問う。",
  114. "「介抱」『内容』【体力】の低いPCが突如、<なにか>に襲われる幻覚を見て取り乱し、偶然現れた【体力】の高いPCに助けられる場面を演出せよ。『終了条件』【体力】の低いPCが感謝の言葉を述べる。",
  115. "「呪印」『内容』PC同士が再会後、【敏捷】の高いPCが、【敏捷】の低いPCの持つ[呪印]に気付く場面を演出せよ。『終了条件』【敏捷】の高いPCが自身にも同じものがあると告げる。",
  116. ]
  117. ),
  118. "AppreciativeFriend" => DiceTable::Table.new(
  119. "知己表",
  120. "2D6",
  121. [
  122. "「大切な人」『内容』PC同士が再会後、事件に関する相談をするうちに、PCが互いに、自身の[大切な人]について語る場面を演出せよ。『終了条件』いずれかのPCが「なんにせよ、その人のためにも、生き残らないといけませんね」と言う。",
  123. "「個人の印象」『内容』PC同士が出会い、事件の相談をするうちに、いずれかが片方のPCの印象や人柄について、感想を述べる場面を演出せよ。『終了条件』感想を言われたPCが「そうかな?」と言う。",
  124. "「呪印について」『内容』PC同士が出会い、お互いの体に刻まれた[呪印]の正体について考える場面を演出せよ。『終了条件』いずれかのPCが、「……結局、謎だらけだということですね。また考えましょうか」と言う。",
  125. "「不安と恐れ」『内容』PC同士が出会い、相談をするうちに【命運】の低いPCが不安を抱き、【命運】の高いPCが気遣う場面を演出せよ。『終了条件』【命運】の低いPCが「大丈夫です」と返す。",
  126. "「情報交換」『内容』PC同士が出会い、現状を整理するために、情報交換を行う場面を演出せよ。『終了条件』いずれかのPCが「……また、新しい情報が手に入ったら連絡します」と言う。",
  127. "「過去と秘密」『内容』PC同士が出会い、事件の相談を行った際、いずれかのPCが[関係性]を結んだ≪過去や秘密≫について語る。『終了条件』≪過去や秘密≫を語ったPCが「巻き込んでしまって、すいません」と言う。",
  128. "「推理」『内容』PC同士が出会い、今回の事件の解決方法について、推理する場面を演出せよ。『終了条件』いずれかのPCが「もっと詳しく調べてみましょう。きっと、なにか良い方法があるはずです」と言う。",
  129. "「協力関係」『内容』PC同士が出会い、いずれかのPCが今回の事件を生き抜くために、より協力関係を強めようと、提案する場面を演出せよ。『終了条件』提案されたほうのPCが、提案に承諾する。",
  130. "「願いについて」『内容』PC同士が出会い、事件について推理するうちに、いずれかのPCが自身の[願い]について語る場面を演出せよ。『終了条件』[願い]を知ったPCが、それに対して個人的な感想を述べる。",
  131. "「作戦会議」『内容』PC同士が出会い、【知性】の低いPCが【知性】の高いPCに良い知恵はないかと相談する場面を演出せよ。『終了条件』【知性】の高いPCが「……上手くいくかわかりませんが、ある方法を試してみます」と言う。",
  132. "「方法はあるはずだ」『内容』PC同士が出会い、いずれかのPCが「生き残る方法は、必ずあるはずだ」と鼓舞する場面を演出せよ。『終了条件』鼓舞されたPCが、「そうですね……その方法を探してみましょう」と言う。",
  133. ]
  134. ),
  135. "Foreshadow" => DiceTable::Table.new(
  136. "伏線表",
  137. "1D6",
  138. [
  139. "PCとの会話のなかで、ふと閃くものがあった。",
  140. "謎の金属片が落ちていた。胸ポケットにしまっておこう。",
  141. "会話の最中……突如、ある真実に気づいてしまった。",
  142. "PCからの激励を耳にして、やけに気合が入った。",
  143. "不安な情報を耳にした瞬間、大切な人の顔が浮かんだ。",
  144. "そのとき、不思議な力が身のうちに宿った。",
  145. ]
  146. ),
  147. "Emotion" => DiceTable::Table.new(
  148. "感情表",
  149. "1D6",
  150. [
  151. "尊敬",
  152. "好意",
  153. "友情",
  154. "庇護",
  155. "信頼",
  156. "安心",
  157. ]
  158. ),
  159. "Situation" => DiceTable::Table.new(
  160. "状況表",
  161. "1D6",
  162. [
  163. "「不運の連鎖」事件が関係しているのか、PCたちの周囲で次々と不幸が起こり始めている。なんとかして、この連鎖を止めなければ……。『使用可能能力値』【幸運】",
  164. "「見えない恐怖」事件が発生してから、PCたちは誰かから監視されているような気がする。こんなときこそ、気を強く持たなければ……。『使用可能能力値』【精神】",
  165. "「冷静な行動」立て続けに起こる怪奇現象のせいで、PCたちはやや混乱気味だ。しかし、こんなときこそ冷静に知恵を絞らねば……。『使用可能能力値』【知性】",
  166. "「震えよ、止まれ」迫りくる恐怖のせいで、PCたちの心身は萎縮し、衰弱している。だが、こんなときこそ冷静に行動しなければ……。『使用可能能力値』【敏捷】",
  167. "「危機はすぐそこ」得体のしれない<なにか>は、間違いなくそこまで迫ってきている。頼れるのはもはや、自分たちの肉体だけだ……。『使用可能能力値』【体力】",
  168. "「運が味方」状況は逼迫しつつある。だが、幸運にも状況がPCたちに味方し始めた。なんとしてでも、このチャンスを活かさねば……。『使用可能能力値』各PCの任意の【能力値】",
  169. ]
  170. ),
  171. "Target" => DiceTable::Table.new(
  172. "対象表",
  173. "1D6",
  174. [
  175. "【体力】が最も高い順",
  176. "【敏捷】が最も高い順",
  177. "【知性】が最も高い順",
  178. "【精神】が最も高い順",
  179. "【幸運】が最も高い順",
  180. "【希望】が最も低い順",
  181. ]
  182. ),
  183. "Insanity" => DiceTable::Table.new(
  184. "狂気表",
  185. "1D6",
  186. [
  187. "「逃げたい」次[フェイズ]の終了を迎えるまで、PCは恐怖のため、その場から一刻も早く立ち去りたいという衝動に駆られる様子を演出せよ。",
  188. "「記憶の混濁」次[フェイズ]の終了を迎えるまで、PCはショックのあまり、見たものや聞いたものが何だったかを思い出せない様子を演出せよ。",
  189. "「興奮状態」次[フェイズ]の終了を迎えるまで、PCは恐怖のあまり、些細なことでイライラし、PCに辛くあたった後、「……ごめんなさい」と、後悔する状況を演出せよ。",
  190. "「怯えている」次[フェイズ]の終了を迎えるまで、PCは恐怖のあまり、先ほどから怯え続けている状況を演出せよ。",
  191. "「緊張状態」次[フェイズ]の終了を迎えるまで、PCは極度の緊張状態で体の自由が利かず、転んだり、萎縮したりする状況を演出せよ。",
  192. "「一時的発狂」次[フェイズ]の終了を迎えるまで、PCは衝撃のあまり、一時的に発狂してしまい、うわごとを何度も何度も繰り返してしまう状況を演出せよ。",
  193. ]
  194. ),
  195. "Death" => DiceTable::Table.new(
  196. "終焉表",
  197. "1D6",
  198. [
  199. "「猟奇殺人」その後、PCは郊外の廃屋のなかでバラバラ死体となって発見された。警察は懸命に捜査を行ったが、結局、手がかりは見つからず、事件は迷宮入りした。",
  200. "「変死」その後、PCが自室で変死しているのが発見された。PCの死因は出血多量。出血を引き起こした外傷は、まるで大きな獣に噛まれたような痕だった。",
  201. "「自殺」その後、PCが郊外に放置された廃車のなかで、自殺しているのが発見された。だが、遺書は見つかっておらず、その理由は最後までわからずじまいであった。",
  202. "「衰弱死」その後、PCは突如として体調を崩し、入院を余儀なくされた。検査を繰り返したものの、原因は不明のまま……やがて、PCは体重が半減して、衰弱死した。",
  203. "「事故死」その後、PCは不慮の事故に遭い、この世を去った。だが、遺体解剖の結果、事故による外傷ではなく、直前に内臓破裂を起こしていたことが判明した。",
  204. "「行方不明」その後、PCは行方不明となった。家族はPCの捜索届を出したが、結局、最後までPCが見つかることはなかった。",
  205. ]
  206. ),
  207. "Fear" => DiceTable::Table.new(
  208. "恐怖表",
  209. "2D6",
  210. [
  211. "「不気味なモノ」血液、人骨のようなもの、大量の粘液など……奇妙なモノが突如、足元に落ちてきた。[効果算出]PC全員に5+[呪印÷2]d。",
  212. "「早まる鼓動」突然のチャイム、突然の電話、突然の呼び声、突然の物音……不安のせいか、ただそれだけで、鼓動が早まる。[効果算出]PC3体に4+[呪印÷2]d。",
  213. "「不安の種」無言電話、差出人不明のメッセージ、鍵穴についた深い傷、排水溝の長い髪の毛など……不安になるものを見つけてしまう。[効果算出]PC1体に4+[呪印÷2]d。",
  214. "「異臭」生臭い匂い、鉄臭い匂い、花のような芳香など……普段嗅がない異臭が、一瞬だけ鼻孔をついた。[効果算出]PC2体に3+[呪印÷2]d。",
  215. "「隙間」建物の影、ベッドの下、ふすまの隙間など……様々な死角から<なにか>の息遣い、気配が漂う。[効果算出]PC2体に2+[呪印÷2]d。",
  216. "「視線」どこからか、強い視線を感じる……だが、そちらに目をやると、気配はすぐに消えてしまった。[効果算出]PC2体に2+[呪印÷2]d。",
  217. "「異音」遠くから不思議な金属音や鐘の音、肉を潰すような音や粘着質な音などが聞こえた気がした。[効果算出]PC2体に3+[呪印÷2]d。",
  218. "「接触」つい先ほど……なにかに触られたような、あるいは服を引っ張られたような気がした。[効果算出]PC3体に3+[呪印÷2]d。",
  219. "「さっきのは?」隣を通り過ぎた人物、声をかけてきた人物、何かを渡してきた人物……しかし、ここには2人以外、誰もいないはずだ。[効果算出]PC2体に4+[呪印÷2]d。",
  220. "「見てはいけない」次の行動に移ろうとしたそのとき、一瞬、通路の向こうに<なにか>が佇んでいるような気がした。[効果算出]PC1体に5+[呪印÷2]d。",
  221. "「暗闇のなかへ」PCは突如として<なにか>に手足をつかまれ、暗闇へと引きずり込まれそうになる![効果算出]PC1体に6+[呪印÷2]d。",
  222. ]
  223. ),
  224. }.transform_keys(&:upcase).freeze
  225. 1 ALIAS = {
  226. "Dai" => "Daily",
  227. "PCi" => "PlaceCity",
  228. "PCo" => "PlaceCountryside",
  229. "PFa" => "PlaceFacility",
  230. "FL" => "FirstLook",
  231. "AF" => "AppreciativeFriend",
  232. "For" => "Foreshadow",
  233. "Emo" => "Emotion",
  234. "Sit" => "Situation",
  235. "Tar" => "Target",
  236. "Ins" => "Insanity",
  237. "Dea" => "Death",
  238. "Fea" => "Fear",
  239. }.transform_keys(&:upcase).transform_values(&:upcase).freeze
  240. 1 register_prefix(TABLES.keys, ALIAS.keys)
  241. end
  242. end
  243. end

lib/bcdice/game_system/Kamigakari.rb

98.95% lines covered

95.0% branches covered

95 relevant lines. 94 lines covered and 1 lines missed.
20 total branches, 19 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Kamigakari < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Kamigakari'
  7. # ゲームシステム名
  8. 1 NAME = '神我狩'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'かみかかり'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・各種表
  14. ・感情表(ET)
  15. ・霊紋消費の代償表(RT)
  16. ・伝奇名字・名前決定表(NT)
  17. ・魔境臨界表(KT)
  18. ・獲得素材チャート(MTx xは[法則障害]の[強度]。省略時は1)
  19.   例) MT MT3 MT9
  20. ・D66ダイスあり
  21. INFO_MESSAGE_TEXT
  22. 1 def initialize(command)
  23. 46 super(command)
  24. 46 @sort_add_dice = true
  25. 46 @d66_sort_type = D66SortType::NO_SORT
  26. end
  27. 1 def eval_game_system_specific_command(command)
  28. 46 tableName = ""
  29. 46 result = ""
  30. 46 debug("eval_game_system_specific_command command", command)
  31. 46 case command.upcase
  32. when: 34 when /^MT(\d*)$/
  33. 34 rank = Regexp.last_match(1)
  34. 34 rank ||= 1
  35. 34 rank = rank.to_i
  36. 34 tableName, result, number = getGetMaterialTableResult(rank)
  37. else: 12 else
  38. 12 return roll_tables(command, self.class::TABLES)
  39. end
  40. 34 then: 0 else: 34 if result.empty?
  41. return ""
  42. end
  43. 34 text = "#{tableName}(#{number}) > #{result}"
  44. 34 return text
  45. end
  46. 1 def getGetMaterialTableResult(rank)
  47. 34 tableName = translate("Kamigakari.MT.name")
  48. 34 table = translate("Kamigakari.MT.items")
  49. 34 result, number = get_table_by_d66(table)
  50. 34 effect, number2 = getMaterialEffect(rank)
  51. 34 number = "#{number},#{number2}"
  52. 34 price = getPrice(effect)
  53. 34 result = translate("Kamigakari.MT.result_format", material: result, effect: effect)
  54. 34 else: 4 then: 30 result += ":#{price}" unless price.nil?
  55. 34 return tableName, result, number
  56. end
  57. 1 def getMaterialEffect(rank)
  58. 34 number = @randomizer.roll_once(6)
  59. 34 result = ""
  60. 34 type = ""
  61. 34 then: 24 if number < 6
  62. 24 result, number2 = getMaterialEffectNomal(rank)
  63. 24 type = translate("Kamigakari.MT.common_material.name")
  64. else: 10 else
  65. 10 result, number2 = getMaterialEffectRare()
  66. 10 type = translate("Kamigakari.MT.rare_material.name")
  67. end
  68. 34 result = "#{type}:#{result}"
  69. 34 number = "#{number},#{number2}"
  70. 34 return result, number
  71. end
  72. 1 def getMaterialEffectNomal(rank)
  73. 24 table = translate("Kamigakari.MT.common_material.items")
  74. 24 number = @randomizer.roll_d66(D66SortType::NO_SORT)
  75. 24 result = get_table_by_number(number, table)
  76. 24 debug("getMaterialEffectNomal result", result)
  77. 24 then: 22 else: 2 if result =~ /\+n/
  78. 22 power, number2 = getMaterialEffectPower(rank)
  79. 22 result = result.sub(/\+n/, "+#{power}")
  80. 22 number = "#{number},#{number2}"
  81. end
  82. 24 return result, number
  83. end
  84. 1 def getMaterialEffectPower(rank)
  85. table = [
  86. 22 [4, [1, 1, 1, 2, 2, 3]],
  87. [8, [1, 1, 2, 2, 3, 3]],
  88. [9, [1, 2, 3, 3, 4, 5]],
  89. ]
  90. 22 then: 4 else: 18 rank = 9 if rank > 9
  91. 22 rankTable = get_table_by_number(rank, table)
  92. 22 power, number = get_table_by_1d6(rankTable)
  93. 22 return power, number
  94. end
  95. 1 def getMaterialEffectRare()
  96. table = [
  97. 10 [3, "**" + translate("Kamigakari.MT.rare_material.give_attribute")], # 付与
  98. [5, "**" + translate("Kamigakari.MT.rare_material.halve_damage")], # 半減
  99. [6, translate("Kamigakari.MT.rare_material.optional_by_GM")],
  100. ]
  101. 10 number = @randomizer.roll_once(6)
  102. 10 result = get_table_by_number(number, table)
  103. 10 debug('getMaterialEffectRare result', result)
  104. 10 then: 8 else: 2 if result.include?("**")
  105. 8 attribute, number2 = getAttribute()
  106. 8 result = result.sub("**", attribute.to_s)
  107. 8 number = "#{number},#{number2}"
  108. end
  109. 10 return result, number
  110. end
  111. 1 def getAttribute()
  112. 8 table = translate("Kamigakari.MT.attribute")
  113. 8 number = @randomizer.roll_d66(D66SortType::NO_SORT)
  114. 8 result = get_table_by_number(number, table)
  115. 8 return result, number
  116. end
  117. 1 def getPrice(effect)
  118. power =
  119. 34 then: 22 if (m = effect.match(/\+(\d+)/))
  120. 22 else: 12 m[1].to_i
  121. 12 then: 4 elsif effect.include?(translate("Kamigakari.MT.rare_material.give_attribute")) # 付与
  122. 4 else: 8 3
  123. 8 then: 4 elsif effect.include?(translate("Kamigakari.MT.rare_material.halve_damage")) # 半減
  124. 4 4
  125. else: 4 else
  126. 4 0
  127. end
  128. table = [
  129. 34 nil,
  130. "500G(#{translate('Kamigakari.MT.effect_power')}:1)",
  131. "1000G(#{translate('Kamigakari.MT.effect_power')}:2)",
  132. "1500G(#{translate('Kamigakari.MT.effect_power')}:3)",
  133. "2000G(#{translate('Kamigakari.MT.effect_power')}:4)",
  134. "3000G(#{translate('Kamigakari.MT.effect_power')}:5)",
  135. ]
  136. 34 price = table[power]
  137. 34 return price
  138. end
  139. 1 class << self
  140. 1 private
  141. 1 def translate_tables(locale)
  142. {
  143. 2 "RT" => DiceTable::Table.from_i18n("Kamigakari.table.RT", locale),
  144. "ET" => DiceTable::D66Table.from_i18n("Kamigakari.table.ET", locale),
  145. "KT" => DiceTable::D66Table.from_i18n("Kamigakari.table.KT", locale),
  146. "NT" => DiceTable::D66Table.from_i18n("Kamigakari.table.NT", locale),
  147. }
  148. end
  149. end
  150. 1 TABLES = translate_tables(:ja_jp)
  151. 1 register_prefix('MT', TABLES.keys)
  152. end
  153. end
  154. end

lib/bcdice/game_system/Kamigakari_Korean.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/Kamigakari"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Kamigakari_Korean < Kamigakari
  6. # ゲームシステムの識別子
  7. 1 ID = 'Kamigakari:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '카미가카리'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:카미가카리'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・각종표
  15. ・감정표(ET)
  16. ・영문소비의 댓가표(RT)
  17. ・전기 성씨・이름 결정표(NT)
  18. ・마경임계표(KT)
  19. ・획득 소재 차트(MTx x는[법칙장해]의[강도].생략할 때는1)
  20.   예) MT MT3 MT9
  21. ・D66주사위 가능
  22. INFO_MESSAGE_TEXT
  23. 1 register_prefix_from_super_class()
  24. 1 def initialize(command)
  25. 23 super(command)
  26. 23 @locale = :ko_kr
  27. end
  28. 1 TABLES = translate_tables(:ko_kr).freeze
  29. end
  30. end
  31. end

lib/bcdice/game_system/KamitsubakiCityUnderConstructionNarrative.rb

98.94% lines covered

96.88% branches covered

94 relevant lines. 93 lines covered and 1 lines missed.
32 total branches, 31 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class KamitsubakiCityUnderConstructionNarrative < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'KamitsubakiCityUnderConstructionNarrative'
  7. # ゲームシステム名
  8. 1 NAME = '神椿市建設中。NARRATIVE'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'かみつはきしけんせつちゆうならていふ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・可組(KA)
  14.  KA6 行動判定
  15.  KA8 技能ロール
  16.  KA10 特技ロール
  17.  KA12 Aロール
  18. ・裏組(RI)
  19.  RI6 行動判定
  20.  RI8 技能ロール
  21.  RI10 特技ロール
  22.  RI12 Aロール
  23. ・羽組(HA)
  24.  HA6 行動判定
  25.  HA8 技能ロール
  26.  HA10 特技ロール
  27.  HA12 Aロール
  28. ・星組(SE)
  29.  SE6 行動判定
  30.  SE8 技能ロール
  31.  SE10 特技ロール
  32.  SE12 Aロール
  33. ・狐組(CO)
  34.  CO6 行動判定
  35.  CO8 技能ロール
  36.  CO10 特技ロール
  37.  CO12 Aロール
  38. ・GM用
  39.  GM6 (成否判定なし)
  40.  GM8 技能ロール
  41.  GM10 特技ロール
  42.  Q12 Qロール
  43. ・存在証明 EXI<=x
  44.  存在証明の判定を行う
  45.  x: 存在値
  46. INFO_MESSAGE_TEXT
  47. 1 def eval_game_system_specific_command(command)
  48. 113 roll_kumi(command) || roll_existence(command)
  49. end
  50. 1 private
  51. 1 def roll_kumi(command)
  52. 113 table = TABLES[command]
  53. 113 else: 104 then: 9 unless table
  54. 9 return nil
  55. end
  56. 104 return table.roll(@randomizer)
  57. end
  58. 1 class KumiDice
  59. 1 def initialize(items)
  60. 17 @items = items.freeze
  61. end
  62. 1 CRITICAL = "M"
  63. 1 FUMBLE = "Q"
  64. 1 def roll(randomizer)
  65. 91 dice = randomizer.roll_once(@items.length)
  66. 91 chosen = @items[dice - 1]
  67. 91 fumble = chosen == FUMBLE
  68. 91 critical = chosen == CRITICAL
  69. result_tail =
  70. 91 then: 19 if fumble
  71. 19 else: 72 "ファンブル"
  72. 72 then: 28 elsif critical
  73. 28 else: 44 "マジック"
  74. 44 then: 24 elsif !chosen.empty?
  75. 24 "成功"
  76. else: 20 else
  77. 20 "失敗"
  78. end
  79. 91 Result.new.tap do |r|
  80. 91 r.critical = critical
  81. 91 r.fumble = fumble
  82. 91 r.condition = !chosen.empty? && !r.fumble?
  83. 91 r.text = [
  84. "(D#{@items.length})",
  85. dice,
  86. 91 then: 20 else: 71 chosen.empty? ? nil : chosen,
  87. result_tail
  88. ].compact.join(" > ")
  89. end
  90. end
  91. end
  92. 1 class KumiD6
  93. 1 def initialize(success_symbol)
  94. 6 @success_symbol = success_symbol
  95. end
  96. 1 TABLE = ["裏", "羽", "星", "狐", "可", "Q"].freeze
  97. 1 def roll(randomizer)
  98. 8 dice = randomizer.roll_once(6)
  99. 8 chosen = TABLE[dice - 1]
  100. 8 Result.new.tap do |r|
  101. 8 else: 1 then: 7 unless @success_symbol.nil?
  102. 7 r.fumble = chosen == "Q"
  103. 7 r.condition = chosen == @success_symbol
  104. end
  105. result_tail =
  106. 8 then: 1 if r.fumble?
  107. 1 else: 7 "ファンブル"
  108. 7 then: 5 elsif r.success?
  109. 5 else: 2 "成功"
  110. 2 then: 1 else: 1 elsif r.failure?
  111. 1 "失敗"
  112. end
  113. 8 r.text = [
  114. "(D6)",
  115. dice,
  116. chosen,
  117. result_tail
  118. ].compact.join(" > ")
  119. end
  120. end
  121. end
  122. 1 class QDice
  123. 1 def initialize(items)
  124. 1 @items = items.freeze
  125. end
  126. 1 CRITICAL = "M"
  127. 1 def roll(randomizer)
  128. 5 dice = randomizer.roll_once(@items.length)
  129. 5 chosen = @items[dice - 1]
  130. 5 critical = chosen == CRITICAL
  131. result_tail =
  132. 5 then: 2 if critical
  133. 2 else: 3 "マジック"
  134. 3 then: 2 elsif !chosen.empty?
  135. 2 "成功"
  136. else: 1 else
  137. 1 "失敗"
  138. end
  139. 5 Result.new.tap do |r|
  140. 5 r.critical = critical
  141. 5 r.condition = !chosen.empty?
  142. 5 r.text = [
  143. "(D#{@items.length})",
  144. dice.to_s,
  145. 5 then: 1 else: 4 chosen.empty? ? nil : chosen,
  146. result_tail,
  147. ].compact.join(" > ")
  148. end
  149. end
  150. end
  151. 1 def roll_existence(command)
  152. 9 m = /^EXI<=(\d+)$/.match(command)
  153. 9 else: 9 then: 0 unless m
  154. return nil
  155. end
  156. 9 target = m[1].to_i
  157. 9 dice = @randomizer.roll_once(20)
  158. 9 Result.new.tap do |r|
  159. 9 r.critical = dice == 1
  160. 9 r.fumble = dice == 20
  161. 9 r.condition = (dice <= target && !r.fumble?) || r.critical?
  162. result_tail =
  163. 9 then: 1 if r.critical?
  164. 1 else: 8 "M > マジック"
  165. 8 then: 2 elsif r.fumble?
  166. 2 else: 6 "Q > ファンブル"
  167. 6 then: 3 elsif r.success?
  168. 3 "成功"
  169. else: 3 else
  170. 3 "失敗"
  171. end
  172. 9 r.text = [
  173. "(D20<=#{target})",
  174. dice,
  175. result_tail
  176. ].join(" > ")
  177. end
  178. end
  179. TABLES = {
  180. 1 "KA6" => KumiD6.new("可"),
  181. "KA8" => KumiDice.new(["Q", "", "", "", "可", "可", "可", "M"]),
  182. "KA10" => KumiDice.new(["Q", "", "", "可", "可", "可", "可", "可", "M", "M"]),
  183. "KA12" => KumiDice.new(["Q", "", "", "可", "可", "可", "可", "可", "可", "可", "M", "M"]),
  184. "RI6" => KumiD6.new("裏"),
  185. "RI8" => KumiDice.new(["Q", "", "", "", "裏", "裏", "裏", "M"]),
  186. "RI10" => KumiDice.new(["Q", "", "", "裏", "裏", "裏", "裏", "裏", "M", "M"]),
  187. "RI12" => KumiDice.new(["M", "M", "裏", "裏", "裏", "裏", "裏", "裏", "裏", "", "", "Q"]),
  188. "HA6" => KumiD6.new("羽"),
  189. "HA8" => KumiDice.new(["Q", "", "", "", "羽", "羽", "羽", "M"]),
  190. "HA10" => KumiDice.new(["Q", "", "", "羽", "羽", "羽", "羽", "羽", "M", "M"]),
  191. "HA12" => KumiDice.new(["Q", "Q", "羽", "羽", "羽", "", "", "", "M", "M", "M", "M"]),
  192. "SE6" => KumiD6.new("星"),
  193. "SE8" => KumiDice.new(["Q", "", "", "", "星", "星", "星", "M"]),
  194. "SE10" => KumiDice.new(["Q", "", "", "星", "星", "星", "星", "星", "M", "M"]),
  195. "SE12" => KumiDice.new(["星", "", "星", "星", "M", "Q", "M", "星", "星", "星", "", "星"]),
  196. "CO6" => KumiD6.new("狐"),
  197. "CO8" => KumiDice.new(["Q", "", "", "", "狐", "狐", "狐", "M"]),
  198. "CO10" => KumiDice.new(["Q", "", "", "狐", "狐", "狐", "狐", "狐", "M", "M"]),
  199. "CO12" => KumiDice.new(["Q", "", "", "狐狐狐", "狐狐", "狐", "狐狐狐", "狐狐", "狐", "狐", "M", "M"]),
  200. "GM6" => KumiD6.new(nil),
  201. "GM8" => KumiDice.new(["Q", "", "", "", "W", "W", "W", "M"]),
  202. "GM10" => KumiDice.new(["Q", "", "", "W", "W", "W", "W", "W", "M", "M"]),
  203. "Q12" => QDice.new(["", "", "", "Q", "Q", "Q", "Q", "Q", "Q", "Q", "M", "M"])
  204. }.freeze
  205. 1 register_prefix("EXI", TABLES.keys)
  206. end
  207. end
  208. end

lib/bcdice/game_system/KanColle.rb

87.01% lines covered

65.0% branches covered

77 relevant lines. 67 lines covered and 10 lines missed.
20 total branches, 13 branches covered and 7 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/dice_table/table'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class KanColle < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'KanColle'
  8. # ゲームシステム名
  9. 1 NAME = '艦これRPG'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'かんこれRPG'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. 例) 2D6 : 単純に2D6した値を出します。
  15. 例) 2D6>=7 : 行為判定。2D6して目標値7以上出れば成功。
  16. 例) 2D6+2>=7 : 行為判定。2D6に修正+2をした上で目標値7以上になれば成功。
  17. 2D6での行為判定時は1ゾロでファンブル、6ゾロでスペシャル扱いになります。
  18. 天龍ちゃんスペシャルは手動で判定してください。
  19. ・各種表
  20.  ・感情表 ET/アクシデント表 ACT
  21.  ・日常イベント表 EVNT/交流イベント表 EVKT/遊びイベント表 EVAT
  22.   演習イベント表 EVET/遠征イベント表 EVENT/作戦イベント表 EVST
  23.  ・ほのぼのイベント表 ETHT/航海イベント表 ETVT 外出イベント表 ETGT
  24.   激戦イベント表 ETBT/任務イベント表 ETMT/恐怖イベント表 ETFT/侵攻効果表 ETIT
  25.  ・大規模部隊表 LSFT/艦隊敗北表 LFDT/艦隊勝利表 LFVT
  26.  ・開発表 DVT/開発表(一括)DVTM
  27.    装備1種表 WP1T/装備2種表 WP2T/装備3種表 WP3T/装備4種表 WP4T
  28.  ・アイテム表 ITT/目標表 MHT/戦果表 SNT/特殊戦果表 SPSNT
  29. ・ランダム個性分野 BT, RCT
  30.  ・ランダム個性選択: 一括 KTM, RTTn (n:分野番号)
  31.    1.背景 KHT/2.魅力 KMT/3.性格 KST/4.趣味 KSYT/5.航海 KKT/ 6.戦闘 KSNT
  32.  ・戦場表 SNZ 暴走表/RNT
  33.  ・特殊開発表 WPMC (燃料6/弾薬3/鋼材6/ボーキ3)
  34.  ・新・特殊開発表 WPMCN
  35.  ・艦載機関開発表 WPFA (燃料3/弾薬6/鋼材3/ボーキ6)
  36.  ・砲類開発表 WPCN (燃料3/弾薬6/鋼材6/ボーキ3)
  37.  ・敵深海棲艦の装備決定 BT2~BT12
  38. ・D66ダイス(D66S相当=低い方が10の桁になる)
  39. INFO_MESSAGE_TEXT
  40. 1 def initialize(command)
  41. 77 super(command)
  42. 77 @sort_add_dice = true
  43. 77 @sort_barabara_dice = true
  44. 77 @d66_sort_type = D66SortType::ASC
  45. end
  46. 1 def result_2d6(_total, dice_total, _dice_list, cmp_op, _target)
  47. 13 else: 13 then: 0 return nil unless cmp_op == :>=
  48. 13 then: 3 if dice_total <= 2
  49. 3 else: 10 Result.fumble("ファンブル(判定失敗。アクシデント表を自分のPCに適用)")
  50. 10 then: 3 else: 7 elsif dice_total >= 12
  51. 3 Result.critical("スペシャル(判定成功。【行動力】が1D6点回復)")
  52. end
  53. end
  54. 1 def eval_game_system_specific_command(command)
  55. 59 output = '1'
  56. 59 type = ""
  57. 59 total_n = ""
  58. 59 case command
  59. when: 1 when 'DVT'
  60. 1 type = '開発表'
  61. 1 output, total_n = get_develop_table
  62. when: 1 when 'DVTM'
  63. 1 type = '開発表(一括)'
  64. 1 output, total_n = get_develop_matome_table
  65. when: 1 when 'WP1T'
  66. 1 type = '装備1種表'
  67. 1 output, total_n = get_weapon1_table
  68. when: 1 when 'WP2T'
  69. 1 type = '装備2種表'
  70. 1 output, total_n = get_weapon2_table
  71. when: 1 when 'WP3T'
  72. 1 type = '装備3種表'
  73. 1 output, total_n = get_weapon3_table
  74. when: 1 when 'WP4T'
  75. 1 type = '装備4種表'
  76. 1 output, total_n = get_weapon4_table
  77. else: 53 else
  78. 53 return roll_tables(command, TABLES) || RTT.roll_command(@randomizer, command)
  79. end
  80. 6 return "#{type}(#{total_n}) > #{output}"
  81. end
  82. 1 RTT = DiceTable::SaiFicSkillTable.new([
  83. ['背景', ['人脈', '名声', '暗い過去', '古風', '口ぐせ', '幸運', 'アイドル', '秘密兵器', 'お嬢様', 'スタイル', '外国暮らし',]],
  84. ['魅力', ['素直', 'クール', '優しい', 'おしとやか', 'けなげ', '笑顔', 'ばか', 'さわやか', '面白い', 'えっち', '派手',]],
  85. ['性格', ['不思議', 'おおらか', '面倒見', 'マジメ', '負けず嫌い', '元気', '楽観的', '丁寧', 'いじわる', '自由奔放', '大胆',]],
  86. ['趣味', ['寝る', '空想', '生き物', '読書', '食べ物', 'おしゃべり', '買い物', '芸能', 'おしゃれ', '入浴', '恋愛',]],
  87. ['航海', ['暗号', '通信', '索敵', '規律', '補給', '待機', '機動', '海図', '指揮', '衛生', '整備',]],
  88. ['戦闘', ['電子戦', '航空打撃戦', '航空戦', '対空戦闘', '突撃', '砲撃', '退却', '支援', '魚雷', '対潜戦闘', '夜戦',]],
  89. ], rtt: "KTM", rct: "BT", rttn: ["KHT", "KMT", "KST", "KSYT", "KKT", "KSNT"],
  90. rtt_format: "個性:一括(%<category_dice>d,%<row_dice>d) > %<text>s",
  91. rct_format: "個性:分野表(%<category_dice>d) > %<category_name>s",
  92. rttn_format: "個性:%<category_name>s表(%<row_dice>d) > %<skill_name>s")
  93. 1 def get_develop_table
  94. 1 table = [
  95. '装備1種表(WP1T)',
  96. '装備1種表(WP1T)',
  97. '装備2種表(WP2T)',
  98. '装備2種表(WP2T)',
  99. '装備3種表(WP3T)',
  100. '装備4種表(WP4T)',
  101. ]
  102. 1 return get_table_by_1d6(table)
  103. end
  104. 1 def get_develop_matome_table
  105. 1 output1 = ''
  106. 1 output2 = ''
  107. 1 total_n2 = ""
  108. 1 dice = @randomizer.roll_once(6)
  109. 1 else: 0 case dice
  110. when: 0 when 1
  111. output1 = '装備1種表'
  112. output2, total_n2 = get_weapon1_table
  113. when: 0 when 2
  114. output1 = '装備1種表'
  115. output2, total_n2 = get_weapon1_table
  116. when: 0 when 3
  117. output1 = '装備2種表'
  118. output2, total_n2 = get_weapon2_table
  119. when: 0 when 4
  120. output1 = '装備2種表'
  121. output2, total_n2 = get_weapon2_table
  122. when: 0 when 5
  123. output1 = '装備3種表'
  124. output2, total_n2 = get_weapon3_table
  125. when: 1 when 6
  126. 1 output1 = '装備4種表'
  127. 1 output2, total_n2 = get_weapon4_table
  128. end
  129. 1 result = "#{output1}:#{output2}"
  130. 1 number = "#{dice},#{total_n2}"
  131. 1 return result, number
  132. end
  133. 1 def get_weapon1_table
  134. 1 table = [
  135. '小口径主砲(P249)',
  136. '10cm連装高角砲(P249)',
  137. '中口径主砲(P249)',
  138. '15.2cm連装砲(P249)',
  139. '20.3cm連装砲(P249)',
  140. '魚雷(P252)',
  141. ]
  142. 1 return get_table_by_1d6(table)
  143. end
  144. 1 def get_weapon2_table
  145. 1 table = [
  146. '副砲(P250)',
  147. '8cm高角砲(P250)',
  148. '大口径主砲(P249)',
  149. '41cm連装砲(P250)',
  150. '46cm三連装砲(P250)',
  151. '機銃(P252)',
  152. ]
  153. 1 return get_table_by_1d6(table)
  154. end
  155. 1 def get_weapon3_table
  156. 1 table = [
  157. '艦上爆撃機(P250)',
  158. '艦上攻撃機(P251)',
  159. '艦上戦闘機(P251)',
  160. '偵察機(P251)',
  161. '電探(P252)',
  162. '25mm連装機銃(P252)',
  163. ]
  164. 1 return get_table_by_1d6(table)
  165. end
  166. 1 def get_weapon4_table
  167. 2 table = [
  168. '彗星(P250)',
  169. '天山(P251)',
  170. '零式艦戦52型(P251)',
  171. '彩雲(P251)',
  172. '61cm四連装(酸素)魚雷(P252)',
  173. '改良型艦本式タービン(P252)',
  174. ]
  175. 2 return get_table_by_1d6(table)
  176. end
  177. TABLES = {
  178. 1 "ET" => DiceTable::Table.new(
  179. "感情表",
  180. "1D6",
  181. [
  182. "かわいい(プラス)/むかつく(マイナス)",
  183. "すごい(プラス)/ざんねん(マイナス)",
  184. "たのしい(プラス)/こわい(マイナス)",
  185. "かっこいい(プラス)/しんぱい(マイナス)",
  186. "いとしい(プラス)/かまってほしい(マイナス)",
  187. "だいすき(プラス)/だいっきらい(マイナス)",
  188. ]
  189. ),
  190. "ACT" => DiceTable::Table.new(
  191. "アクシデント表",
  192. "1D6",
  193. [
  194. "よかったぁ。何もなし。",
  195. "意外な手応え。その判定に使った個性の属性(【長所】と【弱点】)が反対になる。自分が判定を行うとき以外はこの効果は無視する。",
  196. "えーん。大失態。このキャラクターに対して【感情値】を持っているキャラクター全員の声援欄にチェックが入る。",
  197. "奇妙な猫がまとわりつく。サイクルの終了時、もしくは、艦隊戦の終了時まで、自分の行う行為判定にマイナス1の修正がつく(この効果は、マイナス2まで累積する)。",
  198. "いててて。損傷が一つ発生する。もしも艦隊戦中なら、自分と同じ航行序列にいる味方艦にも損傷が一つ発生する。",
  199. "ううう。やりすぎちゃった!自分の【行動力】が1D6点減少する。",
  200. ]
  201. ),
  202. "EVNT" => DiceTable::Table.new(
  203. "日常イベント表",
  204. "2D6",
  205. [
  206. "何もない日々:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は、《待機/航海7》で判定。(着任p220)",
  207. "ティータイム:《外国暮らし/背景12》で判定。(着任p220)",
  208. "釣り:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《おおらか/性格3》で判定。(着任p220)",
  209. "お昼寝:《寝る/趣味2》で判定。(着任p220)",
  210. "綺麗におそうじ!:《衛生/航海11》で判定。(着任p220)",
  211. "海軍カレー:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《食べ物/趣味6》で判定。(着任p220)",
  212. "銀蝿/ギンバイ:《規律/航海5》で判定。(着任p220)",
  213. "日々の訓練:《素直/魅力2》で判定。(着任p220)",
  214. "取材:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《名声/背景3》で判定。(着任p220)",
  215. "海水浴:《突撃/戦闘6》で判定。(着任p220)",
  216. "マイブーム:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《口ぐせ/背景6》で判定。(着任p220)",
  217. ]
  218. ),
  219. "EVKT" => DiceTable::Table.new(
  220. "交流イベント表",
  221. "2D6",
  222. [
  223. "一触即発!:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《笑顔/魅力7》で判定。(着任p221)",
  224. "手取り足取り:自分以外の好きなPC1人を選んで、《えっち/魅力11》で判定。(着任p221)",
  225. "恋は戦争:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《恋愛/趣味12》で判定。(着任p221)",
  226. "マッサージ:自分以外の好きなPC1人を選んで、《けなげ/魅力6》で判定。(着任p221)",
  227. "裸のつきあい:《入浴/趣味11》で判定。(着任p221)",
  228. "深夜のガールズトーク:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《おしゃべり/趣味7》で判定。(着任p221)",
  229. "いいまちがえ:《ばか/魅力8》で判定。(着任p221)",
  230. "小言百より慈愛の一語:自分以外の好きなPC1人を選んで、《面倒見/性格4》で判定。(着任p221)",
  231. "差し入れ:自分以外の好きなPC1人を選んで、提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《優しい/魅力4》で判定。(着任p221)",
  232. "お手紙:自分以外の好きなPC1人を選んで、《古風/背景5》で判定。(着任p221)",
  233. "昔語り:自分以外の好きなPC1人を選んで、提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《暗い過去/背景4》で判定。(着任p221)",
  234. ]
  235. ),
  236. "EVAT" => DiceTable::Table.new(
  237. "遊びイベント表",
  238. "2D6",
  239. [
  240. "遊びのつもりが……:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《さわやか/魅力9》で判定。(着任p222)",
  241. "新しい遊びの開発:《空想/趣味3》で判定。(着任p222)",
  242. "宴会:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《元気/性格7》で判定。(着任p222)",
  243. "街をぶらつく:《面白い/魅力10》で判定。(着任p222)",
  244. "ガールズコーデ:《おしゃれ/趣味10》で判定。(着任p222)",
  245. "○○大会開催!:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《大胆/性格12》で判定。(着任p222)",
  246. "チェス勝負:自分以外の好きなPC1人を選んで、《クール/魅力3》で判定。(着任p222)",
  247. "熱唱カラオケ大会:《芸能/趣味9》で判定。(着任p222)",
  248. "アイドルコンサート:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《アイドル/背景8》で判定。(着任p222)",
  249. "スタイル自慢!:《スタイル/背景11》で判定。(着任p222)",
  250. "ちゃんと面倒みるから!:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《生き物/趣味4》で判定。(着任p222)",
  251. ]
  252. ),
  253. "EVET" => DiceTable::Table.new(
  254. "演習イベント表",
  255. "2D6",
  256. [
  257. "大げんか!:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《負けず嫌い/性格6》で判定。(着任p223)",
  258. "雷撃演習:《魚雷/戦闘10》で判定。(着任p223)",
  259. "座学の講義:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《マジメ/性格5》で判定。(着任p223)",
  260. "速力演習:《機動/航海8》で判定。(着任p223)",
  261. "救援演習:《支援/戦闘9》で判定。シーンプレイヤーのPCは、経験点を10点獲得する。残念:PC全員の【行動力】が1D6点減少する。(着任p223)",
  262. "砲撃演習:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《砲撃/戦闘7》で判定。(着任p223)",
  263. "艦隊戦演習:《派手/魅力12》で判定。(着任p223)",
  264. "整備演習:《整備/航海12》で判定。(着任p223)",
  265. "夜戦演習:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《夜戦/戦闘12》で判定。(着任p223)",
  266. "開発演習:《秘密兵器/背景9》で判定。(着任p223)",
  267. "防空射撃演習:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《対空戦闘/戦闘5》で判定。(着任p223)",
  268. ]
  269. ),
  270. "EVENT" => DiceTable::Table.new(
  271. "遠征イベント表",
  272. "2D6",
  273. [
  274. "謎の深海棲艦:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《退却/戦闘8》で判定。(着任p224)",
  275. "資源輸送任務:《買い物/趣味8》で判定。(着任p224)",
  276. "強行偵察任務:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《索敵/航海4》で判定。(着任p224)",
  277. "航空機輸送作戦:《航空戦/戦闘4》で判定。(着任p224)",
  278. "タンカー護衛任務:《丁寧/性格9》で判定。(着任p224)",
  279. "海上護衛任務:提督が選んだ(キーワード)に対応した指定能力で判定。思いつかない場合は《不思議/性格2》で判定。(着任p224)",
  280. "観艦式:《おしとやか/魅力5》で判定。(着任p224)",
  281. "ボーキサイト輸送任務:《補給/航海6》で判定。(着任p224)",
  282. "社交界デビュー?:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《お嬢様/背景10》で判定。(着任p224)",
  283. "対潜警戒任務:《対潜戦闘/戦闘11》で判定。(着任p224)",
  284. "大規模遠征作戦、発令!:提督の選んだ(キーワード)に対応した指定能力値で判定。思いつかな場合は《指揮/航海10》で判定。(着任p224)",
  285. ]
  286. ),
  287. "EVST" => DiceTable::Table.new(
  288. "作戦イベント表",
  289. "2D6",
  290. [
  291. "電子の目:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《電子戦/戦闘2》で判定。(着任p225)",
  292. "直掩部隊:《航空戦/戦闘4》で判定。(着任p225)",
  293. "噂によれば:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《通信/航海3》で判定。(着任p225)",
  294. "資料室にて:《海図/航海9》で判定。(着任p225)",
  295. "守護天使:《幸運/背景7》で判定。(着任p225)",
  296. "作戦会議!:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《自由奔放/性格11》で判定。(着任p225)",
  297. "暗号解読:《暗号/航海2》で判定。(着任p225)",
  298. "一か八か?:《楽観的/性格8》で判定。(着任p225)",
  299. "特務機関との邂逅:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《人脈/背景2》で判定。(着任p225)",
  300. "クイーンズ・ギャンビット:《いじわる/性格10》で判定。(着任p225)",
  301. "知彼知己者、百戦不殆:《読書/趣味5》で判定。(着任p225)",
  302. ]
  303. ),
  304. "ETHT" => DiceTable::Table.new(
  305. "ほのぼのイベント表",
  306. "2D6",
  307. [
  308. "模様替え:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《派手/魅力12》で判定。(建造弐p134)",
  309. "門限破り:《夜戦/戦闘12》で判定。(建造弐p134)",
  310. "ぼやき大会:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《いじわる/性格10》で判定。(建造弐p134)",
  311. "もしも……:《自由奔放/性格11》で判定。(建造弐p134)",
  312. "退屈な会議:《暗号/航海2》で判定。(建造弐p134)",
  313. "気の合う趣味:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《面白い/魅力10》で判定。(建造弐p134)",
  314. "身だしなみ:《さわやか/魅力9》で判定。(建造弐p134)",
  315. "ダイエット:《スタイル/背景11》で判定。(建造弐p134)",
  316. "通信販売:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《待機/背景2》で判定。(建造弐p134)",
  317. "気になる視線:《えっち/魅力11》で判定。(建造弐p134)",
  318. "思い立ったが吉日:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《恋愛/趣味12》で判定。(建造弐p134)",
  319. ]
  320. ),
  321. "ETVT" => DiceTable::Table.new(
  322. "航海イベント表",
  323. "2D6",
  324. [
  325. "厳しくいくぞ:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《規律/航海5》で判定。(建造弐p135)",
  326. "密航者:《笑顔/魅力7》で判定。(建造弐p135)",
  327. "不審の目:《外国暮らし/背景12》で判定。(建造弐p135)",
  328. "危険海域:《海図/航海9》で判定。(建造弐p135)",
  329. "波間の影:《砲撃/戦闘7》で判定。(建造弐p135)",
  330. "ホームシック:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《支援/戦闘9》で判定。(建造弐p135)",
  331. "追跡者:《対潜戦闘/戦闘11》で判定。(建造弐p135)",
  332. "大嵐:《機動/航海8》で判定。(建造弐p135)",
  333. "うち捨てられた基地:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《読書/趣味5》で判定。(建造弐p135)",
  334. "ネズミ上陸:《衛生/航海11》で判定。(建造弐p135)",
  335. "味の探求:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《読書/趣味5》で判定。(建造弐p135)",
  336. ]
  337. ),
  338. "ETGT" => DiceTable::Table.new(
  339. "外出イベント表",
  340. "2D6",
  341. [
  342. "ノブレス・オブリージュ:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《お嬢様/背景10》で判定。(建造弐p136)",
  343. "サイン会:《名声/背景3》で判定。(建造弐p136)",
  344. "蚤の市:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《古風/背景5》で判定。(建造弐p136)",
  345. "追っかけ:《退却/戦闘8》で判定。(建造弐p136)",
  346. "走り込み:《航空戦/戦闘4》で判定。(建造弐p136)",
  347. "外食:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《索敵/航海4》で判定。(建造弐p136)",
  348. "迷子:《面倒見/性格4》で判定。(建造弐p136)",
  349. "街頭モデル:《おしゃれ/趣味10》で判定。(建造弐p136)",
  350. "暴れ○○だ!:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《生き物/趣味4》で判定。(建造弐p136)",
  351. "臨時講師:《おしゃべり/性格10》で判定。(建造弐p136)",
  352. "映画撮影:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《芸能/趣味9》で判定。(建造弐p136)",
  353. ]
  354. ),
  355. "ETBT" => DiceTable::Table.new(
  356. "激戦イベント表",
  357. "2D6",
  358. [
  359. "分裂の危機:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《指揮/航海10》で判定。(建造弐p137)",
  360. "脱走:《通信/航海3》で判定。(建造弐p137)",
  361. "勇気の呪文:《口ぐせ/背景6》で判定。(建造弐p137)",
  362. "混乱:《整備/航海12》で判定。(建造弐p137)",
  363. "不意の遭遇:《魚雷/戦闘10》で判定。(建造弐p137)",
  364. "敵の襲撃:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《大胆/性格12》で判定。(建造弐p137)",
  365. "対空迎撃戦:《対空戦闘/戦闘5》で判定。(建造弐p137)",
  366. "傷自慢:《元気/性格7》で判定。(建造弐p137)",
  367. "怖がらないで:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《優しい/魅力4》で判定。(建造弐p137)",
  368. "生き延びろ:《負けず嫌い/性格10》で判定。(建造弐p137)",
  369. "極限の集中:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《ばか/魅力8》で判定。(建造弐p137)",
  370. ]
  371. ),
  372. "ETMT" => DiceTable::Table.new(
  373. "任務イベント表",
  374. "2D6",
  375. [
  376. "視察:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《面倒見/魅力12》で判定。(建造弐p138)",
  377. "酒保祭り:《補給/航海6》で判定。(建造弐p138)",
  378. "アイドルユニット結成:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《アイドル/背景8》で判定。(建造弐p138)",
  379. "お風呂場大改造:《入浴/趣味11》で判定。(建造弐p138)",
  380. "現場の融通:《人脈/背景2》で判定。(建造弐p138)",
  381. "緊急空輸:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《航空戦/戦闘4》で判定。(建造弐p138)",
  382. "資源の再利用:《マジメ/性格5》で判定。(建造弐p138)",
  383. "物欲:《買い物/趣味8》で判定。(建造弐p138)",
  384. "魔改造:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《秘密兵器/背景9》で判定。(建造弐p138)",
  385. "ちゃんと伝えたってば!:《クール/魅力3》で判定。(建造弐p138)",
  386. "ストライキ:《おおらか/性格3》で判定。(建造弐p138)",
  387. ]
  388. ),
  389. "ETFT" => DiceTable::Table.new(
  390. "恐怖イベント表",
  391. "2D6",
  392. [
  393. "未知の怪物:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《突撃/戦闘6》で判定。(建造弐p139)",
  394. "ドッペルゲンガー:《不思議/性格2》で判定。(建造弐p139)",
  395. "悪夢:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《寝る/趣味2》で判定。(建造弐p139)",
  396. "イマジナリーフレンド:《空想/趣味3》で判定。(建造弐p139)",
  397. "幽霊船:《電子戦/戦闘2》で判定。(建造弐p139)",
  398. "謎の予言:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《楽観的/性格8》で判定。(建造弐p139)",
  399. "黒猫:《幸運/背景7》で判定。(建造弐p139)",
  400. "サルベージ:《丁寧/性格9》で判定。(建造弐p139)",
  401. "フラッシュバック:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《暗い過去/背景4》で判定。(建造弐p139)",
  402. "深海の呼び声:《素直/魅力2》で判定。(建造弐p139)",
  403. "死者の声:提督が選んだ(キーワード)に対応した指定個性で判定。思いつかない場合は《けなげ/魅力6》で判定。(建造弐p139)",
  404. ]
  405. ),
  406. "BT10" => DiceTable::Table.new(
  407. "指定個性⑩",
  408. "1D6",
  409. [
  410. "1-10 《お嬢様》",
  411. "2-10 《面白い》",
  412. "3-10 《いじわる》",
  413. "4-10 《おしゃれ》",
  414. "5-10 《指揮》",
  415. "6-10 《魚雷》",
  416. ]
  417. ),
  418. "BT11" => DiceTable::Table.new(
  419. "指定個性⑪",
  420. "1D6",
  421. [
  422. "1-11 《スタイル》",
  423. "2-11 《えっち》",
  424. "3-11 《自由奔放》",
  425. "4-11 《入浴》",
  426. "5-11 《衛生》",
  427. "6-11 《対潜戦闘》",
  428. ]
  429. ),
  430. "BT12" => DiceTable::Table.new(
  431. "指定個性⑫",
  432. "1D6",
  433. [
  434. "1-12 《外国暮らし》",
  435. "2-12 《派手》",
  436. "3-12 《大胆》",
  437. "4-12 《恋愛》",
  438. "5-12 《整備》",
  439. "6-12 《夜戦》",
  440. ]
  441. ),
  442. "BT2" => DiceTable::Table.new(
  443. "指定個性②",
  444. "1D6",
  445. [
  446. "1-2 《人脈》",
  447. "2-2 《素直》",
  448. "3-2 《不思議》",
  449. "4-2 《寝る》",
  450. "5-2 《暗号》",
  451. "6-2 《電子戦》",
  452. ]
  453. ),
  454. "BT3" => DiceTable::Table.new(
  455. "指定個性③",
  456. "1D6",
  457. [
  458. "1-3 《名声》",
  459. "2-3 《クール》",
  460. "3-3 《おおらか》",
  461. "4-3 《空想》",
  462. "5-3 《通信》",
  463. "6-3 《航空打撃戦》",
  464. ]
  465. ),
  466. "BT4" => DiceTable::Table.new(
  467. "指定個性④",
  468. "1D6",
  469. [
  470. "1-4 《暗い過去》",
  471. "2-4 《優しい》",
  472. "3-4 《面倒見》",
  473. "4-4 《生き物》",
  474. "5-4 《索敵》",
  475. "6-4 《航空戦》",
  476. ]
  477. ),
  478. "BT5" => DiceTable::Table.new(
  479. "指定個性⑤",
  480. "1D6",
  481. [
  482. "1-5 《古風》",
  483. "2-5 《おしとやか》",
  484. "3-5 《マジメ》",
  485. "4-5 《読書》",
  486. "5-5 《規律》",
  487. "6-5 《対空戦闘》",
  488. ]
  489. ),
  490. "BT6" => DiceTable::Table.new(
  491. "指定個性⑥",
  492. "1D6",
  493. [
  494. "1-6 《口ぐせ》",
  495. "2-6 《けなげ》",
  496. "3-6 《負けず嫌い》",
  497. "4-6 《食べ物》",
  498. "5-6 《補給》",
  499. "6-6 《突撃》",
  500. ]
  501. ),
  502. "BT7" => DiceTable::Table.new(
  503. "指定個性⑦",
  504. "1D6",
  505. [
  506. "1-7 《幸運》",
  507. "2-7 《笑顔》",
  508. "3-7 《元気》",
  509. "4-7 《おしゃべり》",
  510. "5-7 《待機》",
  511. "6-7 《砲撃》",
  512. ]
  513. ),
  514. "BT8" => DiceTable::Table.new(
  515. "指定個性⑧",
  516. "1D6",
  517. [
  518. "1-8 《アイドル》",
  519. "2-8 《ばか》",
  520. "3-8 《楽観的》",
  521. "4-8 《買い物》",
  522. "5-8 《機動》",
  523. "6-8 《退却》",
  524. ]
  525. ),
  526. "BT9" => DiceTable::Table.new(
  527. "指定個性⑨",
  528. "1D6",
  529. [
  530. "1-9 《秘密兵器》",
  531. "2-9 《さわやか》",
  532. "3-9 《丁寧》",
  533. "4-9 《芸能》",
  534. "5-9 《海図》",
  535. "6-9 《支援》",
  536. ]
  537. ),
  538. "ETIT" => DiceTable::Table.new(
  539. "侵攻効果表",
  540. "2D6",
  541. [
  542. "援軍\n深海棲艦は徐々に力をつけ、大艦隊へとせいちょうしつつある。決戦フェイズの深海棲艦側の艦隊に、駆逐ハ級(『着任ノ書p258』)が一人追加される。",
  543. "海域汚染\n特定の海域が深海棲艦の住みやすい環境になる。このセッションの艦隊戦のの各ラウンドの開始時に、深海棲艦の艦隊は誰か一人だけ【行動力】を1D6点減少できるようになる。【行動力】を消費すると、その戦場を好きなものに変更できる。",
  544. "略奪\n大勢の物資や人々を奪い、連れ去られる。鎮守府の資材がすべて1D6個失われる。",
  545. "象徴破壊\n人類に歴史的建造物や貴重な遺産、世界的な観光名所が破壊される。PC全員は【行動力】を1D6点減少する。",
  546. "襲撃\n深海棲艦の侵攻によって、鎮守府の周辺に住む人たちに大きな被害が出る。PC全員は暴走判定を行うこと。",
  547. "通商破壊\n深海棲艦の侵攻によって、通商ルートが破壊される。そのセッションの間、資材を獲得する効果が発生したとき、その資材の数がいずれも一つずつ減少する。",
  548. "謎のキリ\n謎の霧が海域を覆う。このセッションの艦隊戦中、深海棲艦はランドの開始時に、【行動力】を1D6点消費できるようになる。そのラウンドの間、消費した【行動力】の半分の値(切り捨て。0〜3点の値になる)だけ、深海棲艦全員は、艦隊戦で受けるダメージが軽減できる。この効果は累積するが、この効果で軽減できるダメージの上限は3点である。",
  549. "陸地浸食\n陸地を浸食し、海に変える。この事態に鎮守府への非難が高まる。そのセッションの間、PC全員はあらゆる判定にマイナス1の修正がつく。この侵攻以降、行動判定を行うPCは、判定直前に自分の【行動力】を1点消費するたび、進行による修正をすべて打ち消すことができる。",
  550. "新型改造\n深海棲艦は自らを強化しているようだ。そのセッションの決戦フェイズに登場する深海棲艦の中から一人を選ぶ。その深海棲艦をeliteのクラスを付加する。その深海棲艦がすでにeliteならflagshipに、flagshipなら改にすることもできる。",
  551. "艦娘研究\n艦娘が拿捕され、鹵獲される。一体何を企んでいるのか……?提督は、好きなNPCの艦娘を一人選ぶ。深海棲艦の一人に、その艦娘の持つアビリティ一つを習得させることができる。",
  552. "基地建設\n深海棲艦は自分たちの基地を建造した。そのセッションの決戦フェイズで、深海棲艦の旗艦は、開幕雷撃戦と雷撃戦でダメージを受けなくなる。",
  553. ]
  554. ),
  555. "LFDT" => DiceTable::Table.new(
  556. "艦隊敗北表",
  557. "1D6",
  558. [
  559. "敵の支援砲撃。ランダムなPC一人に損傷を一つ与える。",
  560. "敵の罠。ランダムなPC一人に「アクシデント表」を一回適用する。",
  561. "追い詰められる。戦場が「T字戦不利」になる。",
  562. "本隊への合流。「敵部隊のサポート」発生。",
  563. "盟友艦行方不明(MIA)。敵部隊の旗艦が決戦フェイズ中、対応する盟友艦の固有、または戦術アビリティをいずれか一つを修得する。",
  564. "盟友艦轟沈。盟友艦は失われ「暴走表」を一回振り、暴走する。",
  565. ]
  566. ),
  567. "LFVT" => DiceTable::Table.new(
  568. "艦隊勝利表",
  569. "1D6",
  570. [
  571. "支援砲撃。敵艦の中からランダムな一人に損傷を一つ与える。",
  572. "士気高揚。この表を振ったPCの【命中力】が1点上昇する。",
  573. "士気高揚。この表を振ったPCの【火力】が1点上昇する。",
  574. "士気高揚。この表を振ったPCの【回避力】が1点上昇する。",
  575. "士気高揚。この表を振ったPCの【装甲力】が1点上昇する。",
  576. "絆が深まる。その盟友艦からのPCへの【感情値】が1点上昇する。",
  577. ]
  578. ),
  579. "LSFT" => DiceTable::Table.new(
  580. "大規模部隊表",
  581. "1D6",
  582. [
  583. "水上打撃部隊 「脅威力:10」",
  584. "空母機動部隊 「脅威力:9」",
  585. "水雷戦隊    「脅威力:8」",
  586. "潜水艦部隊   「脅威力:7」",
  587. "輸送部隊 「脅威力:6」",
  588. "主力部隊 「脅威力:12」",
  589. ]
  590. ),
  591. "WPCN" => DiceTable::Table.new(
  592. "砲開発表(燃料3/弾薬6/鋼材6/ボーキ3)",
  593. "4D6",
  594. [
  595. "開発失敗!(資材だけ失う)",
  596. "開発失敗!(資材だけ失う)",
  597. "三式弾(建造壱p169)",
  598. "25mm連装機銃(着任p252)",
  599. "41cm連装砲(着任p250)",
  600. "8cm高角砲(着任p250)",
  601. "15.2cm連装砲(着任p249)",
  602. "魚雷(着任p252)",
  603. "機銃(着任p252)",
  604. "小口径主砲(着任p249)",
  605. "中口径主砲(着任p249)",
  606. "小口径主砲(着任p249)",
  607. "中口径主砲(着任p249)",
  608. "10cm連装高角砲(着任p249)",
  609. "20.3cm連装砲(着任p249)",
  610. "61cm四連装(酸素)魚雷(着任p252)",
  611. "46cm三連装砲(着任p250)",
  612. "15.5cm三連装砲(副砲)(建造壱p167)",
  613. "61cm五連装(酸素)魚雷(建造壱p168)",
  614. "53cm艦種(酸素)魚雷(建造壱p168)",
  615. "九一式徹甲弾(建造壱p169)",
  616. ]
  617. ),
  618. "WPFA" => DiceTable::Table.new(
  619. "艦載機開発表(燃料3/弾薬6/鋼材3/ボーキ6)",
  620. "4D6",
  621. [
  622. "開発失敗!(資材だけ失う)",
  623. "開発失敗!(資材だけ失う)",
  624. "開発失敗!(資材だけ失う)",
  625. "開発失敗!(資材だけ失う)",
  626. "開発失敗!(資材だけ失う)",
  627. "Ju87C改(建造壱p167)",
  628. "流星(建造壱p167)",
  629. "紫電改二(建造壱p167)",
  630. "零式艦戦52型(着任p251)",
  631. "艦上戦闘機(着任p251)",
  632. "偵察機(着任p251)",
  633. "艦上爆撃機(着任p250)",
  634. "艦上攻撃機(着任p251)",
  635. "彩雲(着任p251)",
  636. "彗星(着任p250)",
  637. "天山(着任p251)",
  638. "瑞雲(建造壱p168)",
  639. "彗星一二型甲(建造壱p167)",
  640. "流星改(建造壱p167)",
  641. "烈風(建造壱p168)",
  642. "零式水上観測機(建造壱p168)",
  643. ]
  644. ),
  645. "WPMC" => DiceTable::Table.new(
  646. "特殊開発表(燃料6/弾薬3/鋼材6/ボーキ3)",
  647. "2D6",
  648. [
  649. "開発失敗!(資材だけ失う)",
  650. "開発失敗!(資材だけ失う)",
  651. "開発失敗!(資材だけ失う)",
  652. "開発失敗!(資材だけ失う)",
  653. "探照灯(建造壱p169)",
  654. "電探(着任p252)",
  655. "改良型艦本式タービン(着任p252)",
  656. "九四式爆雷投射機(建造壱p169)",
  657. "甲標的 甲(建造壱p168)",
  658. "33号対水上電探(建造壱p169)",
  659. "増設バルジ(中型艦)(建造壱p169)",
  660. ]
  661. ),
  662. "WPMCN" => DiceTable::Table.new(
  663. "新特殊開発表(燃料6/弾薬3/鋼材6/ボーキ3)",
  664. "2D6",
  665. [
  666. "開発失敗!(資材だけ失う)",
  667. "カ号観測機(建造弐p171)",
  668. "九三式水中聴音機(建造弐p171)",
  669. "ドラム缶(輸送用)(建造弐p171)",
  670. "探照灯(建造壱p169)",
  671. "電探(着任p252)",
  672. "改良型艦本式タービン(着任p252)",
  673. "九四式爆雷投射機(建造壱p169)",
  674. "甲標的 甲(建造壱p168)",
  675. "33号対水上電探(建造壱p169)",
  676. "増設バルジ(中型艦)(建造壱p169)",
  677. ]
  678. ),
  679. "ITT" => DiceTable::Table.new(
  680. "アイテム表",
  681. "1D6",
  682. [
  683. "アイス(P241)",
  684. "羊羹(P241)",
  685. "開発資材(P241)",
  686. "高速修復剤(P241)",
  687. "応急修理要員(P241)",
  688. "思い出の品(P241)",
  689. ]
  690. ),
  691. "MHT" => DiceTable::Table.new(
  692. "目標表",
  693. "1D6",
  694. [
  695. "敵艦の中で、もっとも航行序列の高いPC",
  696. "敵艦の中で、もっとも損傷の多いPC",
  697. "敵艦の中で、もっとも【装甲力】の低いPC",
  698. "敵艦の中で、もっとも【回避力】の低いPC",
  699. "敵艦の中で、もっとも【火力】の高いPC",
  700. "敵艦の中から完全にランダムに決定",
  701. ]
  702. ),
  703. "SNT" => DiceTable::Table.new(
  704. "戦果表",
  705. "1D6",
  706. [
  707. "燃料/1D6+[敵艦隊の人数]個",
  708. "弾薬/1D6+[敵艦隊の人数]個",
  709. "鋼材/1D6+[敵艦隊の人数]個",
  710. "ボーキサイト/1D6+[敵艦隊の人数]個",
  711. "任意の資材/1D6+[敵艦隊の人数]個",
  712. "感情値/各自好きなキャラクターへの【感情値】+1",
  713. ]
  714. ),
  715. "SPSNT" => DiceTable::Table.new(
  716. "特殊戦果表",
  717. "1D6",
  718. [
  719. "すべての資材/+3",
  720. "アイテム表(着任p241)から好きなアイテムを取得",
  721. "家具コイン/+1",
  722. "砲類開発表を使用する(資材は消費しない)",
  723. "艦載機開発表を使用する(資材は消費しない)",
  724. "新特殊開発表を使用する(資材は消費しない)",
  725. ]
  726. ),
  727. "SNZ" => DiceTable::Table.new(
  728. "戦場表",
  729. "1D6",
  730. [
  731. "同航戦(P231)",
  732. "反航戦(P231)",
  733. "T字有利(P231)",
  734. "T字不利(P231)",
  735. "悪天候(P231)",
  736. "悪海象(あくかいしょう)(P231)",
  737. ]
  738. ),
  739. "RNT" => DiceTable::Table.new(
  740. "暴走表",
  741. "1D6",
  742. [
  743. "妄想(建造弐p164)",
  744. "狂戦士(建造弐p164)",
  745. "興奮(建造弐p164)",
  746. "溺愛(建造弐p164)",
  747. "慢心(建造弐p164)",
  748. "絶望(建造弐p164)",
  749. ]
  750. ),
  751. }.freeze
  752. 1 register_prefix(
  753. 'DVT', 'DVTM', 'WP1T', 'WP2T', 'WP3T', 'WP4T',
  754. RTT.prefixes,
  755. TABLES.keys
  756. )
  757. end
  758. end
  759. end

lib/bcdice/game_system/Karukami.rb

97.56% lines covered

92.31% branches covered

41 relevant lines. 40 lines covered and 1 lines missed.
13 total branches, 12 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Karukami < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Karukami'
  7. # ゲームシステム名
  8. 1 NAME = 'カルカミ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'かるかみ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~HELP_MESSAGE
  13. ■ 行為判定、ダメージ算出 (xUB+y@c>=t)
  14. 6面ダイスをx個ダイスロールし、クリティカル値以上の出目が出たら振り足して合計値を算出します。
  15. x: ダイス数
  16. y: 修正値(省略可)
  17. c: クリティカル値(省略可)
  18. t: 目標値値(省略可)
  19. 例)2UB, 2UB>=7, 3UB+1@5, 3UB+1@5<10
  20. HELP_MESSAGE
  21. 1 register_prefix('\d+UB')
  22. 1 def eval_game_system_specific_command(command)
  23. 15 roll_ub(command)
  24. end
  25. 1 def roll_ub(command)
  26. 15 parser = Command::Parser.new("UB", round_type: @round_type)
  27. .has_prefix_number
  28. .enable_critical
  29. 15 parsed = parser.parse(command)
  30. 15 else: 15 then: 0 unless parsed
  31. return nil
  32. end
  33. 15 critical = parsed.critical || 6
  34. 15 then: 1 else: 14 if critical <= 1
  35. 1 return "(#{parsed}) > クリティカル値は2以上としてください"
  36. end
  37. 14 list_list = []
  38. 14 criticals = 0
  39. 14 stack = parsed.prefix_number
  40. 14 body: 20 while stack > 0
  41. 20 dice_list = @randomizer.roll_barabara(stack, 6)
  42. 20 list_list.push(dice_list)
  43. 57 stack = dice_list.count { |x| x >= critical }
  44. 20 criticals += stack
  45. end
  46. 14 total = list_list.flatten.sum() + parsed.modify_number
  47. result =
  48. 14 then: 3 if list_list.first.all?(1)
  49. 3 total = 0
  50. 3 else: 11 Result.fumble("ファンブル")
  51. 11 then: 5 elsif parsed.cmp_op.nil?
  52. 5 else: 6 Result.new()
  53. 6 then: 3 elsif total.send(parsed.cmp_op, parsed.target_number)
  54. 3 Result.success("成功")
  55. else: 3 else
  56. 3 Result.failure("失敗")
  57. end
  58. 14 result.critical = criticals > 0
  59. sequence = [
  60. 14 "(#{parsed})",
  61. 20 *list_list.map { |list| "[#{list.join(',')}]" },
  62. total,
  63. 14 then: 5 else: 9 ("#{criticals}クリティカル" if result.critical?),
  64. result.text,
  65. ].compact
  66. 14 result.text = sequence.join(" > ")
  67. 14 return result
  68. end
  69. end
  70. end
  71. end

lib/bcdice/game_system/KemonoNoMori.rb

100.0% lines covered

90.48% branches covered

48 relevant lines. 48 lines covered and 0 lines missed.
21 total branches, 19 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/dice_table/table'
  3. 1 require 'bcdice/dice_table/range_table'
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class KemonoNoMori < Base
  7. # ゲームシステムの識別子
  8. 1 ID = 'KemonoNoMori'
  9. # ゲームシステム名
  10. 1 NAME = '獸ノ森'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = 'けもののもり'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = <<~MESSAGETEXT
  15. ・行為判定(成功度自動算出)(P119): KAx[±y]
  16. ・継続判定(成功度+1固定): KCx[±y]
  17. x=目標値
  18. y=目標値への修正(任意) x+y-z のように複数指定可能
  19. 例1)KA7+3 → 目標値7にプラス3の修正を加えた行為判定
  20. 例2)KC6 → 目標値6の継続判定
  21. ・罠動作チェック+獲物表(P163): CTR
  22. 罠ごとに1D12を振り、12が出た場合には生き物が罠を動作させ、その影響を受けている。
  23. ・各種表(基本ルールブック)
  24. ・大失敗表(P120): FT
  25. ・能力値ランダム決定表(P121): RST
  26. ・ランダム所要時間表(P122): RTT
  27. ・ランダム消耗表(P122): RET
  28. ・ランダム天気表(P128): RWT
  29. ・ランダム天気持続表(P128): RWDT
  30. ・ランダム遮蔽物表(屋外)(P140): ROMT
  31. ・ランダム遮蔽物表(屋内)(P140): RIMT
  32. ・逃走体験表(P144): EET
  33. ・食材採集表(P157): GFT
  34. ・水採集表(P157): GWT
  35. ・白の魔石効果表(P186): WST
  36. ・部位ダメージ関連の表(参照先ページはリプレイ&データブック「嚙神ノ宴」のもの)
  37. ・人間部位表(P216): HPT
  38. ・部位ダメージ段階表(P217): PDT
  39. ・四足動物部位表(P225): QPT
  40. ・無足動物部位表(P225): APT
  41. ・二足動物部位表(P226): TPT
  42. ・鳥部位表(P226): BPT
  43. ・頭足動物部位表(P227): CPT
  44. ・昆虫部位表(P227): IPT
  45. ・蜘蛛部位表(P228): SPT
  46. MESSAGETEXT
  47. 1 def eval_game_system_specific_command(command)
  48. 89 when: 11 case command
  49. 11 when: 9 when /KA\d[-+\d]*/ then check_1D12(command, true)
  50. 9 when: 6 when /KC\d[-+\d]*/ then check_1D12(command, false)
  51. 6 when: 3 when 'CTR' then get_trap_result()
  52. 3 else: 60 when 'EET' then get_escape_experience_table_result(command)
  53. 60 else roll_tables(command, TABLES)
  54. end
  55. end
  56. 1 def check_1D12(command, is_action_judge)
  57. 20 debug('獸ノ森の1d12判定')
  58. 20 m = /K[AC](\d[-+\d]*)/.match(command)
  59. 20 else: 20 then: 0 return nil unless m
  60. # 修正込みの目標値を計算
  61. 20 target_total = ArithmeticEvaluator.eval(m[1])
  62. 20 debug('target_total', target_total)
  63. # 行為判定の成功度は [目標値の10の位の数+1]
  64. # 継続判定の成功度は固定で+1
  65. 20 then: 11 else: 9 success_degree = is_action_judge ? target_total / 10 + 1 : 1
  66. 20 dice_total = @randomizer.roll_once(12)
  67. 20 debug('dice_total, target_total, success_degree = ', dice_total, target_total, success_degree)
  68. 20 then: 2 if dice_total == 12
  69. 2 else: 18 Result.fumble("(1D12<=#{target_total}) > #{dice_total} > 大失敗")
  70. 18 then: 6 elsif dice_total == 11
  71. 6 else: 12 Result.critical("(1D12<=#{target_total}) > #{dice_total} > 大成功(成功度+#{success_degree}, 次の継続判定の目標値を10に変更)")
  72. 12 then: 10 elsif dice_total <= target_total
  73. 10 Result.success("(1D12<=#{target_total}) > #{dice_total} > 成功(成功度+#{success_degree})")
  74. else: 2 else
  75. 2 Result.failure("(1D12<=#{target_total}) > #{dice_total} > 失敗")
  76. end
  77. end
  78. 1 def get_trap_result()
  79. 6 tra_check_num = @randomizer.roll_once(12)
  80. 6 else: 3 then: 3 unless tra_check_num == 12
  81. 3 return Result.new("罠動作チェック(1D12) > #{tra_check_num} > 罠は動作していなかった")
  82. end
  83. 3 chase_num = @randomizer.roll_once(12)
  84. 3 when: 1 else: 0 chase = case chase_num
  85. 1 when: 1 when 1, 2, 3, 4 then '小型動物'
  86. 1 when: 1 when 5, 6, 7, 8 then '大型動物'
  87. 1 when 9, 10, 11, 12 then '人間の放浪者'
  88. end
  89. 3 Result.new("罠動作チェック(1D12) > #{tra_check_num} > 罠が動作していた! > 獲物表(#{chase_num}) > #{chase}が罠にかかっていた")
  90. end
  91. 1 def get_escape_experience_table_result(command)
  92. 3 escape_experience = roll_tables(command, TABLES)
  93. 3 escape_duration = @randomizer.roll_once(12)
  94. 3 Result.new("#{escape_experience} (再登場: #{escape_duration}時間後)")
  95. end
  96. TABLES = {
  97. 1 'FT' => DiceTable::RangeTable.new(
  98. '大失敗表',
  99. '1D12',
  100. [
  101. [1..3, '【余裕】が3点減少する(最低0まで)'],
  102. [4..5, 'ランダムな荷物1個が落ちて行方不明になる(大失敗したエリアのアイテム調査で見つけることが可能)'],
  103. [6..7, 'ランダムな荷物1個が破壊される'],
  104. [8..9, 'ランダム天気表(RWT)を使用し、結果をターンの終了まで適用する'],
  105. [10, 'ランダムな準備している小道具1個が破壊される'],
  106. [11, '着装している防具が破壊される'],
  107. [12, '準備している武器が破壊される'],
  108. ]
  109. ),
  110. 'RST' => DiceTable::RangeTable.new(
  111. '能力値ランダム決定表',
  112. '1D12',
  113. [
  114. [1..2, '【移動】'],
  115. [3..4, '【格闘】'],
  116. [5..6, '【射撃】'],
  117. [7..8, '【製作】'],
  118. [9..10, '【察知】'],
  119. [11..12, '【自制】'],
  120. ]
  121. ),
  122. 'RTT' => DiceTable::RangeTable.new(
  123. 'ランダム所要時間表',
  124. '1D12',
  125. [
  126. [1..3, '2'],
  127. [4..6, '3'],
  128. [7..9, '4'],
  129. [10..12, '5'],
  130. ]
  131. ),
  132. 'RET' => DiceTable::RangeTable.new(
  133. 'ランダム消耗表',
  134. '1D12',
  135. [
  136. [1..3, '0'],
  137. [4..6, '1'],
  138. [7..9, '2'],
  139. [10..12, '4'],
  140. ]
  141. ),
  142. 'RWT' => DiceTable::RangeTable.new(
  143. 'ランダム天気表',
  144. '1D12',
  145. [
  146. [1..2, '濃霧'],
  147. [3..4, '大雨'],
  148. [5..6, '雷雨'],
  149. [7..8, '強風'],
  150. [9..10, '酷暑'],
  151. [11..12, '極寒'],
  152. ]
  153. ),
  154. 'RWDT' => DiceTable::RangeTable.new(
  155. 'ランダム天気持続表',
  156. '1D12',
  157. [
  158. [1..2, '1ターン'],
  159. [3..4, '3ターン'],
  160. [5..6, '6ターン'],
  161. [7..8, '24ターン'],
  162. [9..10, '72ターン'],
  163. [11..12, '156ターン'],
  164. ]
  165. ),
  166. 'ROMT' => DiceTable::RangeTable.new(
  167. 'ランダム遮蔽物表(屋外)',
  168. '1D12',
  169. [
  170. [1..2, '【藪】耐久度3,軽減値1,特殊効果:コンタクト内のキャラクターに対する射撃攻撃判定に-1の修正を付加'],
  171. [3..5, '【木】耐久度5,軽減値2,特殊効果:コンタクト内のキャラクターに対する射撃攻撃判定に-1の修正を付加'],
  172. [6..8, '【大木】耐久度7,軽減値3,特殊効果:コンタクト内のキャラクターに対する射撃攻撃判定に-2の修正を付加'],
  173. [9..10, '【岩】耐久度6,軽減値4,特殊効果:コンタクト内のキャラクターに対する射撃攻撃判定に-1の修正を付加/コンタクト内で行われる格闘攻撃のダメージ+1'],
  174. [11..12, '【岩壁】耐久度8,軽減値4,特殊効果:コンタクト内のキャラクターに対する射撃攻撃判定に-2の修正を付加/コンタクト内で行われる格闘攻撃のダメージ+2'],
  175. ]
  176. ),
  177. 'RIMT' => DiceTable::RangeTable.new(
  178. 'ランダム遮蔽物表(屋内)',
  179. '1D12',
  180. [
  181. [1..4, '【木材の壁】耐久度4,軽減値2,特殊効果:コンタクト内のキャラクターに対する射撃攻撃判定に-1の修正を付加'],
  182. [5..8, '【木材の扉】耐久度4,軽減値2,特殊効果:コンタクト内のキャラクターに対する射撃攻撃判定に-1、接触判定と突撃判定に-2の修正を付加'],
  183. [9..12, '【木製家具】耐久度3,軽減値2,特殊効果:コンタクト内で行われる格闘攻撃のダメージ+1'],
  184. ]
  185. ),
  186. 'EET' => DiceTable::RangeTable.new(
  187. '逃走体験表',
  188. '1D12',
  189. [
  190. [1..3, '【余裕】が0になる'],
  191. [4..6, '任意の【絆】を合計2点減少する'],
  192. [7..9, '全ての荷物を失う(逃走したエリアに配置され、調査で発見可能)'],
  193. [10..12, '全ての武器と防具と小道具と荷物を失う(逃走したエリアに配置され、調査で発見可能)'],
  194. ]
  195. ),
  196. 'GFT' => DiceTable::RangeTable.new(
  197. '食材採集表',
  198. '1D12',
  199. [
  200. [1..2, '食べられる根(栄養価:2)'],
  201. [3..5, '食べられる草(栄養価:3)'],
  202. [6..8, '食べられる実(栄養価:5)'],
  203. [9..10, '小型動物(栄養価:10)'],
  204. [11, '大型動物(栄養価:40)'],
  205. [12, '気持ち悪い虫(栄養価:1)'],
  206. ]
  207. ),
  208. 'GWT' => DiceTable::RangeTable.new(
  209. '水採集表',
  210. '1D12',
  211. [
  212. [1..6, '汚水'],
  213. [7..11, '飲料水'],
  214. [12, '毒水'],
  215. ]
  216. ),
  217. 'WST' => DiceTable::Table.new(
  218. '白の魔石効果表',
  219. '1D12',
  220. [
  221. '役に立たないものの色を変える',
  222. '役に立たないものを大きくする',
  223. '役に立たないものを小さくする',
  224. '役に立たないものを保存する',
  225. '役に立たないものを復元する',
  226. '役に立たないものを召喚する',
  227. '役に立たないものを動かす',
  228. '役に立たないものを増やす',
  229. '役に立たないものを貼り付ける',
  230. '役に立たないものを作り出す',
  231. '小型動物を召喚する',
  232. '大型動物を召喚する',
  233. ]
  234. ),
  235. 'HPT' => DiceTable::RangeTable.new(
  236. '人間部位表',
  237. '1D12',
  238. [
  239. [1..2, '右腕部'],
  240. [3..4, '左腕部'],
  241. [5..6, '右脚部'],
  242. [7..8, '左脚部'],
  243. [9..11, '胴部'],
  244. [12, '頭部'],
  245. ]
  246. ),
  247. 'PDT' => DiceTable::RangeTable.new(
  248. '部位ダメージ段階表',
  249. '1D12',
  250. [
  251. [1..6, '軽傷'],
  252. [7..10, '重傷'],
  253. [11, '破壊'],
  254. [12, '喪失'],
  255. ]
  256. ),
  257. 'QPT' => DiceTable::RangeTable.new(
  258. '四足動物部位表',
  259. '1D12',
  260. [
  261. [1..2, '異形'],
  262. [3, '武器'],
  263. [4, '右前脚部'],
  264. [5, '左前脚部'],
  265. [6, '右後脚部'],
  266. [7, '左後脚部'],
  267. [8..10, '胴部'],
  268. [11..12, '頭部'],
  269. ]
  270. ),
  271. 'APT' => DiceTable::RangeTable.new(
  272. '無足動物部位表',
  273. '1D12',
  274. [
  275. [1..3, '異形'],
  276. [4..6, '武器'],
  277. [7..10, '胴部'],
  278. [11..12, '頭部'],
  279. ]
  280. ),
  281. 'TPT' => DiceTable::RangeTable.new(
  282. '二足動物部位表',
  283. '1D12',
  284. [
  285. [1, '異形'],
  286. [2, '武器'],
  287. [3, '右腕部'],
  288. [4, '左腕部'],
  289. [5..6, '右脚部'],
  290. [7..8, '左脚部'],
  291. [9..11, '胴部'],
  292. [12, '頭部'],
  293. ]
  294. ),
  295. 'BPT' => DiceTable::RangeTable.new(
  296. '鳥部位表',
  297. '1D12',
  298. [
  299. [1, '異形'],
  300. [2, '武器'],
  301. [3..4, '右翼(右腕部)'],
  302. [5..6, '左翼(左腕部)'],
  303. [7, '右脚部'],
  304. [8, '左脚部'],
  305. [9..11, '胴部'],
  306. [12, '頭部'],
  307. ]
  308. ),
  309. 'CPT' => DiceTable::RangeTable.new(
  310. '頭足動物部位表',
  311. '1D12',
  312. [
  313. [1, '異形'],
  314. [2, '武器'],
  315. [3, '右腕部'],
  316. [4, '左腕部'],
  317. [5..7, '右脚部'],
  318. [8..10, '左脚部'],
  319. [11, '胴部'],
  320. [12, '頭部'],
  321. ]
  322. ),
  323. 'IPT' => DiceTable::RangeTable.new(
  324. '昆虫部位表',
  325. '1D12',
  326. [
  327. [1..2, '異形'],
  328. [3, '武器'],
  329. [4, '右前脚部'],
  330. [5, '左前脚部'],
  331. [6, '右中脚部'],
  332. [7, '左中脚部'],
  333. [8, '右後脚部'],
  334. [9, '左後脚部'],
  335. [10..11, '胴部'],
  336. [12, '頭部'],
  337. ]
  338. ),
  339. 'SPT' => DiceTable::RangeTable.new(
  340. '蜘蛛部位表',
  341. '1D12',
  342. [
  343. [1, '異形'],
  344. [2, '武器'],
  345. [3, '右第一脚部'],
  346. [4, '左第一脚部'],
  347. [5, '右第二脚部'],
  348. [6, '左第二脚部'],
  349. [7, '右第三脚部'],
  350. [8, '左第三脚部'],
  351. [9, '右第四脚部'],
  352. [10, '左第四脚部'],
  353. [11, '胴部'],
  354. [12, '頭部'],
  355. ]
  356. ),
  357. }.freeze
  358. 1 register_prefix('K[AC]', 'CTR', TABLES.keys)
  359. end
  360. end
  361. end

lib/bcdice/game_system/KillDeathBusiness.rb

97.6% lines covered

85.71% branches covered

250 relevant lines. 244 lines covered and 6 lines missed.
77 total branches, 66 branches covered and 11 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class KillDeathBusiness < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'KillDeathBusiness'
  7. # ゲームシステム名
  8. 1 NAME = 'キルデスビジネス'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'きるてすひしねす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定
  14.  JDx or JDx±y or JDx,z JDx#z or JDx±y,z JDx±y#z
  15.  (x=難易度、y=補正、z=ファンブル率(リスク))
  16. ・履歴表 (HST)
  17. ・願い事表 (-WT)
  18.  死(DWT)、復讐(RWT)、勝利(VWT)、獲得(PWT)、支配(CWT)、繁栄(FWT)
  19.  強化(IWT)、健康(HWT)、安全(SAWT)、長寿(LWT)、生(EWT)
  20. ・万能命名表 (NAME, NAMEx) xに数字(1,2,3)で表を個別ロール
  21. ・サブプロット表 (-SPT)
  22.  オカルト(OSPT)、家族(FSPT)、恋愛(LOSPT)、正義(JSPT)、修行(TSPT)
  23.  笑い(BSPT)、意地悪(MASPT)、恨み(UMSPT)、人気(POSPT)、仕切り(PASPT)
  24.  金儲け(MOSPT)、対悪魔(ANSPT)
  25. ・シーン表 (ST)、サービスシーン表 (EST)
  26. ・CM表 (CMT)
  27. ・蘇生副作用表 (ERT)
  28. ・一週間表(WKT)
  29. ・ソウル放出表 (SOUL)
  30. ・汎用演出表 (STGT)
  31. ・ヘルスタイリスト罵倒表 (HSAT、HSATx) xに数字(1,2)で表を個別ロール
  32. ・指定特技ランダム決定表 (SKLT, RTTn nは分野番号)、指定特技分野ランダム決定表 (RCT, SKLJ)
  33. ・エキストラ表 (EXT、EXTx) xに数字(1,2,3,4)で表を個別ロール
  34. ・製作委員決定表 PCDT/実際どうだったのか表 OHT
  35. ・タスク表 ヘルライオン PCT1/ヘルクロウ PCT2/ヘルスネーク PCT3/
  36.  ヘルドラゴン PCT4/ヘルフライ PCT5/ヘルゴート PCT6/ヘルベア PCT7
  37. ・大喜利スペシャル表 (-OT)
  38.  お題決定表(TOT)、〇〇を見て一言表(OOT)
  39.  単語表(WOT, WOTx) xに英字(A,B,C)で単語表A(人物)(AOT)、単語表B(物)(BOT)、単語表C(場所)を個別ロール
  40.  動詞表(VOT)、長め単語表(LOT)
  41.  ヘル司会者 リアクション表(好印象ver)(POT)、ヘル司会者 リアクション表(不満ver)(NOT)
  42. ・D66ダイスあり
  43. INFO_MESSAGE_TEXT
  44. 1 def initialize(command)
  45. 302 super(command)
  46. 302 @sort_add_dice = true
  47. 302 @d66_sort_type = D66SortType::ASC
  48. end
  49. # ゲーム別成功度判定(2D6)
  50. 1 def result_2d6(_total, dice_total, _dice_list, cmp_op, _target)
  51. 14 else: 14 then: 0 return nil unless cmp_op == :>=
  52. 14 then: 4 if dice_total <= 2
  53. 4 else: 10 Result.fumble(translate("KillDeathBusiness.fumble"))
  54. 10 then: 4 else: 6 elsif dice_total >= 12
  55. 4 Result.critical(translate("KillDeathBusiness.special"))
  56. end
  57. end
  58. 1 def eval_game_system_specific_command(command)
  59. 287 debug("eval_game_system_specific_command command", command)
  60. 287 then: 42 if command.start_with?("JD")
  61. 42 judgeDice(command)
  62. else: 245 else
  63. 245 rollTableCommand(command)
  64. end
  65. end
  66. 1 private
  67. 1 def judgeDice(command)
  68. 42 fumble_match = /,(\d+)$/.match(command)
  69. 42 parser = Command::Parser.new(/JD\d+/, round_type: round_type)
  70. .enable_critical
  71. .enable_fumble
  72. .restrict_cmp_op_to(nil)
  73. 42 then: 29 else: 13 cmd = parser.parse(fumble_match&.pre_match || command)
  74. 42 else: 42 then: 0 unless cmd
  75. return nil
  76. end
  77. 42 target = cmd.command.delete_prefix("JD").to_i
  78. 42 modify = cmd.modify_number
  79. 42 then: 29 else: 13 fumble = fumble_match ? fumble_match[1].to_i : cmd.fumble.to_i
  80. 42 command = judge_expr(target, modify, fumble)
  81. 42 result = ""
  82. 42 then: 4 else: 38 if target > 12
  83. 4 result += "【#{command}】 > #{translate('KillDeathBusiness.JD.warning.over_target_number')}\n"
  84. 4 target = 12
  85. end
  86. 42 then: 2 else: 40 if target < 5
  87. 2 result += "【#{command}】 > #{translate('KillDeathBusiness.JD.warning.min_target_is_five')}\n"
  88. 2 target = 5
  89. end
  90. 42 then: 12 if fumble < 2
  91. 12 else: 30 fumble = 2
  92. 30 then: 4 else: 26 elsif fumble > 11
  93. 4 result += "【#{command}】 > #{translate('KillDeathBusiness.JD.warning.over_fumble')}\n"
  94. 4 fumble = 11
  95. end
  96. 42 dice_list = @randomizer.roll_barabara(2, 6)
  97. 42 number = dice_list.sum()
  98. 42 diceText = dice_list.join(",")
  99. 42 result += [
  100. translate("KillDeathBusiness.JD.options", target: target, modifier: modify, fumble: fumble),
  101. " > ",
  102. translate("KillDeathBusiness.JD.dice_value", dice_value: diceText),
  103. " > ",
  104. ].join("")
  105. 42 then: 0 if number == 2
  106. else: 42 result += translate("KillDeathBusiness.JD.fumble")
  107. 42 then: 2 elsif number == 12
  108. 2 else: 40 result += translate("KillDeathBusiness.JD.special")
  109. 40 then: 16 elsif number <= fumble
  110. 16 result += translate("KillDeathBusiness.JD.less_than_fumble_target")
  111. else: 24 else
  112. 24 number += modify
  113. 24 then: 11 if number < target
  114. 11 result += translate("KillDeathBusiness.JD.failure", value: number)
  115. else: 13 else
  116. 13 result += translate("KillDeathBusiness.JD.success", value: number)
  117. end
  118. end
  119. 42 return translate("KillDeathBusiness.JD.name") + result
  120. end
  121. 1 def judge_expr(target, modifier, fumble)
  122. 42 modifier = Format.modifier(modifier)
  123. 42 then: 30 else: 12 fumble = ",#{fumble}" if fumble > 0
  124. 42 "JD#{target}#{modifier}#{fumble}"
  125. end
  126. 1 def rollTableCommand(command)
  127. 245 command = ALIAS[command] || command
  128. 245 result = roll_tables(command, self.class::TABLES) || self.class::RTT.roll_command(@randomizer, command)
  129. 245 then: 172 else: 73 return result if result
  130. 73 tableName = ""
  131. 73 result = ""
  132. 73 else: 0 case command
  133. when /^ST(\d)?$/
  134. when: 12 # シーン表
  135. 12 type = Regexp.last_match(1).to_i
  136. 12 tableName, result, number = getSceneTableResult(type)
  137. when /^NAME(\d)?$/
  138. when: 16 # 万能命名表
  139. 16 type = Regexp.last_match(1).to_i
  140. 16 tableName, result, number = getNameTableResult(type)
  141. when /^EST$/i, /^sErviceST$/i
  142. when: 7 # サービスシーン表
  143. 7 tableName, result, number = getServiceSceneTableResult()
  144. when /^HSAT(\d)?$/
  145. when: 12 # ヘルスタイリスト罵倒表
  146. 12 type = Regexp.last_match(1).to_i
  147. 12 tableName, result, number = getHairStylistAbuseTableResult(type)
  148. when /^EXT(\d)?$/
  149. when: 2 # エキストラ表
  150. 2 type = Regexp.last_match(1).to_i
  151. 2 tableName, result, number = getExtraTableResult(type)
  152. when /^TOT?$/
  153. when: 6 # お題決定表
  154. 6 tableName, result, number = getThemeTableResult()
  155. when /^OOT?$/
  156. when: 3 # 一言決定表
  157. 3 tableName, result, number = getOneWordTableResult()
  158. when /^WOT?$/
  159. when: 3 # 単語決定表
  160. 3 tableName, result, number = getWordTableResult()
  161. when /^POT?$/
  162. when: 6 # ヘル司会者 リアクション表(好印象ver)
  163. 6 tableName, result, number = getPositiveTableResult()
  164. when /^NOT?$/
  165. when: 6 # ヘル司会者 リアクション表(不満ver)
  166. 6 tableName, result, number = getNegativeTableResult()
  167. end
  168. 73 then: 0 else: 73 if result.empty?
  169. return ""
  170. end
  171. 73 text = "#{tableName}(#{number}) > #{result}"
  172. 73 return text
  173. end
  174. 1 def getSceneTableResult(type)
  175. 12 debug("getSceneTableResult type", type)
  176. 12 tableName = translate("KillDeathBusiness.ST.name")
  177. 12 sceneTable1 = translate("KillDeathBusiness.ST.table1")
  178. 12 sceneTable2 = translate("KillDeathBusiness.ST.table2")
  179. 12 result = ''
  180. 12 number = 0
  181. 12 case type
  182. when: 4 when 1
  183. 4 result, number = get_table_by_d66_swap(sceneTable1)
  184. when: 4 when 2
  185. 4 result, number = get_table_by_d66_swap(sceneTable2)
  186. else: 4 else
  187. 4 result1, num1 = get_table_by_d66_swap(sceneTable1)
  188. 4 result2, num2 = get_table_by_d66_swap(sceneTable2)
  189. 4 result = translate("KillDeathBusiness.ST.format", result1: result1, result2: result2)
  190. 4 number = "#{num1},#{num2}"
  191. end
  192. 12 return tableName, result, number
  193. end
  194. 1 def getNameTableResult(type)
  195. 17 tableName = translate("KillDeathBusiness.NAME.name")
  196. 17 nameTable1 = translate("KillDeathBusiness.NAME.table1")
  197. 17 nameTable2 = translate("KillDeathBusiness.NAME.table2")
  198. 17 nameTable3 = translate("KillDeathBusiness.NAME.table3")
  199. 17 result = ''
  200. 17 number = 0
  201. 17 case type
  202. when: 4 when 1
  203. 4 result, number = get_table_by_d66_swap(nameTable1)
  204. when: 4 when 2
  205. 4 result, number = get_table_by_d66_swap(nameTable2)
  206. when: 4 when 3
  207. 4 result, number = get_table_by_d66_swap(nameTable3)
  208. else: 5 else
  209. 5 result1, num1 = get_table_by_d66_swap(nameTable1)
  210. 5 result2, num2 = get_table_by_d66_swap(nameTable2)
  211. 5 result3, num3 = get_table_by_d66_swap(nameTable3)
  212. 5 result = "#{result1}#{result2}#{result3}"
  213. 5 number = "#{num1},#{num2},#{num3}"
  214. end
  215. 17 return tableName, result, number
  216. end
  217. 1 def getServiceSceneTableResult()
  218. 7 table_name = translate("KillDeathBusiness.EST.name")
  219. tables = [
  220. 7 translate("KillDeathBusiness.EST.tables.undressing"), # 脱衣系サービスシーン表
  221. translate("KillDeathBusiness.EST.tables.violence"), # 暴力系サービスシーン表
  222. translate("KillDeathBusiness.EST.tables.travel"), # 旅行系サービスシーン表
  223. translate("KillDeathBusiness.EST.tables.love"), # 恋愛系サービスシーン表
  224. translate("KillDeathBusiness.EST.tables.emotion"), # 感動系サービスシーン表
  225. translate("KillDeathBusiness.EST.tables.other_genre"), # 別ジャンルサービスシーン表
  226. ]
  227. 7 number1 = @randomizer.roll_once(6)
  228. 7 scene_table = tables[number1 - 1]
  229. 7 number2 = @randomizer.roll_once(6)
  230. 7 scene = scene_table[:items][number2 - 1]
  231. 7 result = translate("KillDeathBusiness.EST.format", scene: scene_table[:name], chosen: scene)
  232. 7 number = "#{number1}#{number2}"
  233. 7 return table_name, result, number
  234. end
  235. 1 def getHairStylistAbuseTableResult(type)
  236. 12 tableName = translate("KillDeathBusiness.HSAT.name")
  237. 12 hellStylistAbuseTable1 = translate("KillDeathBusiness.HSAT.abuse_table1")
  238. 12 hellStylistAbuseTable2 = translate("KillDeathBusiness.HSAT.abuse_table2")
  239. 12 hellStylistwtable1 = translate("KillDeathBusiness.HSAT.prefix_table")
  240. 12 hellStylistwtable2 = translate("KillDeathBusiness.HSAT.suffix_table")
  241. 12 case type
  242. when: 4 when 1
  243. 4 result, number = get_table_by_d66_swap(hellStylistAbuseTable1)
  244. when: 4 when 2
  245. 4 result, number = get_table_by_d66_swap(hellStylistAbuseTable2)
  246. else: 4 else
  247. 4 result1, num1 = get_table_by_d66_swap(hellStylistAbuseTable1)
  248. 4 result2, num2 = get_table_by_d66_swap(hellStylistAbuseTable2)
  249. 4 before, = get_table_by_1d6(hellStylistwtable1)
  250. 4 after, = get_table_by_1d6(hellStylistwtable2)
  251. 4 result = "#{before}#{result1} #{result2}#{after}"
  252. 4 number = "#{num1},#{num2}"
  253. end
  254. 12 return tableName, result, number
  255. end
  256. 1 def getExtraTableResult(type)
  257. 2 tableName = translate("KillDeathBusiness.EXT.name")
  258. extraTable1 = [
  259. 2 [11, translate("KillDeathBusiness.EXT.table1.11")],
  260. [12, translate("KillDeathBusiness.EXT.table1.12")],
  261. [13, translate("KillDeathBusiness.EXT.table1.13")],
  262. [14, translate("KillDeathBusiness.EXT.table1.14")],
  263. [15, translate("KillDeathBusiness.EXT.table1.15")],
  264. [16, translate("KillDeathBusiness.EXT.table1.16")],
  265. [22, translate("KillDeathBusiness.EXT.table1.22")],
  266. [23, translate("KillDeathBusiness.EXT.table1.23")],
  267. [24, translate("KillDeathBusiness.EXT.table1.24")],
  268. [25, translate("KillDeathBusiness.EXT.table1.25")],
  269. [26, translate("KillDeathBusiness.EXT.table1.26")],
  270. [33, translate("KillDeathBusiness.EXT.table1.33")],
  271. [34, translate("KillDeathBusiness.EXT.table1.34")],
  272. [35, translate("KillDeathBusiness.EXT.table1.35")],
  273. [36, translate("KillDeathBusiness.EXT.table1.36")],
  274. [44, translate("KillDeathBusiness.EXT.table1.44")],
  275. [45, translate("KillDeathBusiness.EXT.table1.45")],
  276. [46, translate("KillDeathBusiness.EXT.table1.46")],
  277. [55, translate("KillDeathBusiness.EXT.table1.55")],
  278. 1 [56, lambda { translate("KillDeathBusiness.EXT.table1.56", name: getNameTableResult(0)[1]) }],
  279. [66, translate("KillDeathBusiness.EXT.table1.66")],
  280. ]
  281. 2 extraTable2 = translate("KillDeathBusiness.EXT.table2")
  282. 2 extraTable3 = translate("KillDeathBusiness.EXT.table3")
  283. 2 extraTable4 = translate("KillDeathBusiness.EXT.table4")
  284. 2 case type
  285. when: 1 when 1
  286. 1 result, number = get_table_by_d66_swap(extraTable1)
  287. when: 0 when 2
  288. result, number = get_table_by_d66_swap(extraTable2)
  289. when: 0 when 3
  290. result, number = get_table_by_d66_swap(extraTable3)
  291. when: 0 when 4
  292. result, number = get_table_by_d66_swap(extraTable4)
  293. else: 1 else
  294. 1 result1, num1 = get_table_by_d66_swap(extraTable1)
  295. 1 result2, num2 = get_table_by_d66_swap(extraTable2)
  296. 1 result3, num3 = get_table_by_d66_swap(extraTable3)
  297. 1 result4, num4 = get_table_by_d66_swap(extraTable4)
  298. 1 result = "#{result1}#{result2}が#{result3}#{result4}"
  299. 1 number = "#{num1},#{num2},#{num3},#{num4}"
  300. end
  301. 2 return tableName, result, number
  302. end
  303. 1 def getThemeTableResult()
  304. 6 tableName = translate("KillDeathBusiness.table.TOT.name")
  305. 6 result = ''
  306. 6 d6 = @randomizer.roll_once(6)
  307. 6 else: 0 case d6
  308. when: 1 when 1
  309. 1 oneTableName, oneResult, oneD6, one = getOneWordTableResult()
  310. 1 result += "[#{oneTableName}]を見て一言。\n#{oneTableName}(#{oneD6}) > #{oneResult}\n> "
  311. 1 result += translate("KillDeathBusiness.table.TOT.items.1", one: one)
  312. when: 1 when 2
  313. 1 word1TableName, word1Result, word1D6, word1 = getWordTableResult()
  314. 1 word2TableName, word2Result, word2D6, word2 = getWordTableResult()
  315. 1 result += "この[#{word1TableName}]、ひょっとして[#{word1TableName}]かも、どうしてそう思った?\n#{word1TableName}(#{word1D6}) > #{word1Result}\n#{word2TableName}(#{word2D6}) > #{word2Result}\n> "
  316. 1 result += translate("KillDeathBusiness.table.TOT.items.2", word1: word1, word2: word2)
  317. when: 1 when 3
  318. 1 vot = self.class::TABLES["VOT"].roll(@randomizer)
  319. 1 verbTableName = vot.table_name
  320. 1 verb = vot.body
  321. 1 number = vot.value
  322. 1 wordTableName, wordResult, wordD6, word = getWordTableResult()
  323. 1 result += "[#{verbTableName}]した[#{wordTableName}]が言いそうなこと。\n#{verbTableName}(#{number}) > #{verb}\n#{wordTableName}(#{wordD6}) > #{wordResult}\n> "
  324. 1 result += translate("KillDeathBusiness.table.TOT.items.3", verb: verb, word: word)
  325. when: 1 when 4
  326. 1 word1TableName, word1Result, word1D6, word1 = getWordTableResult()
  327. 1 word2TableName, word2Result, word2D6, word2 = getWordTableResult()
  328. 1 result += "[#{word1TableName}]が[#{word1TableName}]になった世界ではどんなことが起こる?\n#{word1TableName}(#{word1D6}) > #{word1Result}\n#{word2TableName}(#{word2D6}) > #{word2Result}\n> "
  329. 1 result += translate("KillDeathBusiness.table.TOT.items.4", word1: word1, word2: word2)
  330. when: 1 when 5
  331. 1 wordTableName, wordResult, wordD6, word = getWordTableResult()
  332. 1 result += "こんな[#{wordTableName}]は嫌だ。どんなの?\n#{wordTableName}(#{wordD6}) > #{wordResult}\n> "
  333. 1 result += translate("KillDeathBusiness.table.TOT.items.5", word: word)
  334. when: 1 when 6
  335. 1 lot = self.class::TABLES["LOT"].roll(@randomizer)
  336. 1 longTableName = lot.table_name
  337. 1 long = lot.body
  338. 1 number = lot.value
  339. 1 result += "[#{longTableName}]みたいなことを言って下さい。\n#{longTableName}(#{number}) > #{long}\n> "
  340. 1 result += translate("KillDeathBusiness.table.TOT.items.6", long: long)
  341. end
  342. 6 return tableName, result, d6
  343. end
  344. 1 def getOneWordTableResult()
  345. 4 tableName = translate("KillDeathBusiness.table.OOT.name")
  346. 4 result = ''
  347. 4 d6 = @randomizer.roll_once(6)
  348. 4 else: 0 case d6
  349. when: 1 when 1, 2
  350. 1 oneWord = translate("KillDeathBusiness.table.OOT.items.1")
  351. 1 result = oneWord
  352. when: 1 when 3, 4
  353. 1 oneWord = translate("KillDeathBusiness.table.OOT.items.3")
  354. 1 result = oneWord
  355. when: 2 when 5, 6
  356. 2 wordTableName, wordResult, wordD6, word = getWordTableResult()
  357. 2 result += "[#{wordTableName}]で検索して出てくる6番目の画像\n#{wordTableName}(#{wordD6}) > #{wordResult}\n> "
  358. 2 oneWord = translate("KillDeathBusiness.table.OOT.items.5", word: word)
  359. 2 result += oneWord
  360. end
  361. 4 return tableName, result, d6, oneWord
  362. end
  363. 1 def getWordTableResult()
  364. 11 tableName = "単語表"
  365. 11 d6 = @randomizer.roll_once(6)
  366. table =
  367. 11 else: 0 case d6
  368. when: 1 when 1, 2
  369. 1 self.class::TABLES["WOTA"]
  370. when: 3 when 3, 4
  371. 3 self.class::TABLES["WOTB"]
  372. when: 7 when 5, 6
  373. 7 self.class::TABLES["WOTC"]
  374. end
  375. 11 result = table.roll(@randomizer)
  376. 11 return tableName, result.to_s, d6, result.body
  377. end
  378. 1 def getPositiveTableResult()
  379. 6 tableName = translate("KillDeathBusiness.table.POT.name")
  380. table = [
  381. 7 lambda { return translate("KillDeathBusiness.table.POT.items.1", size: @randomizer.roll_sum(1, 6).to_s) },
  382. 1 lambda { return translate("KillDeathBusiness.table.POT.items.2", size: @randomizer.roll_sum(1, 6).to_s) },
  383. 1 lambda { return translate("KillDeathBusiness.table.POT.items.3", size: @randomizer.roll_sum(2, 6).to_s) },
  384. 1 lambda { return translate("KillDeathBusiness.table.POT.items.4", size: @randomizer.roll_sum(2, 6).to_s) },
  385. translate("KillDeathBusiness.table.POT.items.5"),
  386. 1 lambda { return translate("KillDeathBusiness.table.POT.items.6", size: (@randomizer.roll_sum(1, 6) - 3).to_s) },
  387. ]
  388. 6 result, number = get_table_by_1d6(table)
  389. 6 return tableName, result, number
  390. end
  391. 1 def getNegativeTableResult()
  392. 6 tableName = translate("KillDeathBusiness.table.NOT.name")
  393. table = [
  394. 6 translate("KillDeathBusiness.table.NOT.items.1"),
  395. translate("KillDeathBusiness.table.NOT.items.2"),
  396. 1 lambda { return translate("KillDeathBusiness.table.NOT.items.3", size: @randomizer.roll_sum(1, 6).to_s) },
  397. 1 lambda { return translate("KillDeathBusiness.table.NOT.items.4", size: @randomizer.roll_sum(1, 6).to_s) },
  398. 1 lambda { return translate("KillDeathBusiness.table.NOT.items.5", size: @randomizer.roll_sum(1, 6).to_s) },
  399. translate("KillDeathBusiness.table.NOT.items.6"),
  400. ]
  401. 6 result, number = get_table_by_1d6(table)
  402. 6 return tableName, result, number
  403. end
  404. 1 ALIAS = {
  405. "DeathWT" => "DWT",
  406. "RevengeWT" => "RWT",
  407. "VictoryWT" => "VWT",
  408. "PossesionWT" => "PWT",
  409. "ControlWT" => "CWT",
  410. "FlourishWT" => "FWT",
  411. "IntensifyWT" => "IWT",
  412. "HealthWT" => "HWT",
  413. "SafetyWT" => "SAWT",
  414. "LongevityWT" => "LWT",
  415. "ExistWT" => "EWT",
  416. "OccultSPT" => "OSPT",
  417. "FamilySPT" => "FSPT",
  418. "LoveSPT" => "LOSPT",
  419. "JusticeSPT" => "JSPT",
  420. "TrainingSPT" => "TSPT",
  421. "BeamSPT" => "BSPT",
  422. }.transform_keys(&:upcase).freeze
  423. 1 class << self
  424. 1 private
  425. 1 def translate_tables(locale)
  426. {
  427. 2 "HST" => DiceTable::Table.from_i18n("KillDeathBusiness.table.HST", locale),
  428. "DWT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.DWT", locale),
  429. "RWT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.RWT", locale),
  430. "VWT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.VWT", locale),
  431. "PWT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.PWT", locale),
  432. "CWT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.CWT", locale),
  433. "FWT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.FWT", locale),
  434. "IWT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.IWT", locale),
  435. "HWT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.HWT", locale),
  436. "SAWT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.SAWT", locale),
  437. "LWT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.LWT", locale),
  438. "EWT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.EWT", locale),
  439. "OSPT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.OSPT", locale),
  440. "FSPT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.FSPT", locale),
  441. "LOSPT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.LOSPT", locale),
  442. "JSPT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.JSPT", locale),
  443. "TSPT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.TSPT", locale),
  444. "BSPT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.BSPT", locale),
  445. "CMT" => DiceTable::D66Table.from_i18n("KillDeathBusiness.table.CMT", locale),
  446. "ERT" => DiceTable::D66Table.from_i18n("KillDeathBusiness.table.ERT", locale),
  447. "WKT" => DiceTable::D66Table.from_i18n("KillDeathBusiness.table.WKT", locale),
  448. "SOUL" => DiceTable::Table.from_i18n("KillDeathBusiness.table.SOUL", locale),
  449. "STGT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.STGT", locale),
  450. "PCDT" => DiceTable::D66Table.from_i18n("KillDeathBusiness.table.PCDT", locale),
  451. "OHT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.OHT", locale),
  452. "PCT1" => DiceTable::Table.from_i18n("KillDeathBusiness.table.PCT1", locale),
  453. "PCT2" => DiceTable::Table.from_i18n("KillDeathBusiness.table.PCT2", locale),
  454. "PCT3" => DiceTable::Table.from_i18n("KillDeathBusiness.table.PCT3", locale),
  455. "PCT4" => DiceTable::Table.from_i18n("KillDeathBusiness.table.PCT4", locale),
  456. "PCT5" => DiceTable::Table.from_i18n("KillDeathBusiness.table.PCT5", locale),
  457. "PCT6" => DiceTable::Table.from_i18n("KillDeathBusiness.table.PCT6", locale),
  458. "PCT7" => DiceTable::Table.from_i18n("KillDeathBusiness.table.PCT7", locale),
  459. "ANSPT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.ANSPT", locale),
  460. "MASPT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.MASPT", locale),
  461. "MOSPT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.MOSPT", locale),
  462. "PASPT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.PASPT", locale),
  463. "POSPT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.POSPT", locale),
  464. "UMSPT" => DiceTable::Table.from_i18n("KillDeathBusiness.table.UMSPT", locale),
  465. "WOTA" => DiceTable::D66Table.from_i18n("KillDeathBusiness.table.WOTA", locale),
  466. "WOTB" => DiceTable::D66Table.from_i18n("KillDeathBusiness.table.WOTB", locale),
  467. "WOTC" => DiceTable::D66Table.from_i18n("KillDeathBusiness.table.WOTC", locale),
  468. "VOT" => DiceTable::D66Table.from_i18n("KillDeathBusiness.table.VOT", locale),
  469. "LOT" => DiceTable::D66Table.from_i18n("KillDeathBusiness.table.LOT", locale),
  470. }
  471. end
  472. 1 def translate_rtt(locale)
  473. 2 DiceTable::SaiFicSkillTable.from_i18n("KillDeathBusiness.RTT", locale, rtt: "SKLT", rct: "SKLJ")
  474. end
  475. end
  476. 1 TABLES = translate_tables(:ja_jp)
  477. 1 RTT = translate_rtt(:ja_jp)
  478. 1 register_prefix(
  479. 'ST[1-2]?',
  480. 'NAME[1-3]?',
  481. 'EST', 'sErviceST',
  482. 'HSAT[1-2]?',
  483. 'EXT[1-4]?',
  484. 'JD',
  485. 'TOT',
  486. 'OOT',
  487. 'WOT',
  488. 'POT',
  489. 'NOT'
  490. )
  491. 1 register_prefix(TABLES.keys, register_prefix(ALIAS.keys), RTT.prefixes)
  492. end
  493. end
  494. end

lib/bcdice/game_system/KillDeathBusiness_Korean.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/KillDeathBusiness"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class KillDeathBusiness_Korean < KillDeathBusiness
  6. # ゲームシステムの識別子
  7. 1 ID = 'KillDeathBusiness:Korean'
  8. # ゲームシステム名
  9. 1 NAME = 'Kill Death Business (한국어)'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:Kill Death Business'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・판정
  15.  JDx or JDx+y or JDx-y or JDx,z or JDx+y,z JDx-y,z
  16.  (x=난이도、y=보정、z=펌블도(리스크))
  17. ・이력표 (HST、HSTx) x에 숫자(1,2)로 표를 개별 롤
  18. ・소원표 (-WT)
  19.  죽음(DWT)、복수(RWT)、승리(VWT)、획득(PWT)、지배(CWT)、번영(FWT)
  20.  강화(IWT)、건강(HWT)、안전(SAWT)、장생(LWT)、삶(EWT)
  21. ・만능이름표 (NAME) x에 숫자(1,2,3)로 표를 개별 롤
  22. ・서브플롯표 (-SPT)
  23.  오컬트(OSPT)、가족(FSPT)、연애(LOSPT)、정의(JSPT)、수행(TSPT)
  24.  웃음(BSPT)、심술쟁이(MASPT)、원한(UMSPT)、인기(POSPT)、구분(PASPT)
  25.  돈벌이(MOSPT)、대(対)악마(ANSPT)
  26. ・씬 표 (ST)、서비스 씬 표 (EST)
  27. ・CM표 (CMT)
  28. ・소생 부작용 표 (ERT)
  29. ・일주일간 표(WKT)
  30. ・소울 방출표 (SOUL)
  31. ・범용연출표 (STGT)
  32. ・헬 스타일리스트 매도표 (HSAT、HSATx) x에 숫자(1,2)로 표를 개별 롤
  33. ・지정특기 랜덤 결정표 (RTT, SKLT)、지정특기 분야 랜덤 결정표 (RCT, SKLJ)
  34. ・엑스트라 표 (EXT、EXTx) x에 숫자(1,2,3,4)로 표를 개별 롤
  35. ・제작위원 결정표 PCDT/실제 어떠했는가 표 OHT
  36. ・태스크 표 헬 라이온 PCT1/헬 크로우 PCT2/헬 스네이크 PCT3/
  37.  헬 드래곤 PCT4/헬 플라이 PCT5/헬 갓 PCT6/헬 베어 PCT7
  38. ・D66 다이스 지원
  39. INFO_MESSAGE_TEXT
  40. 1 register_prefix_from_super_class()
  41. 1 def initialize(command)
  42. 133 super(command)
  43. 133 @locale = :ko_kr
  44. end
  45. 1 TABLES = translate_tables(:ko_kr)
  46. 1 RTT = translate_rtt(:ko_kr)
  47. end
  48. end
  49. end

lib/bcdice/game_system/KimitoYell.rb

96.86% lines covered

95.0% branches covered

159 relevant lines. 154 lines covered and 5 lines missed.
80 total branches, 76 branches covered and 4 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class KimitoYell < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "KimitoYell"
  7. # ゲームシステム名
  8. 1 NAME = "キミトエール!"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "きみとええる"
  11. 1 HELP_MESSAGE = <<~TEXT
  12. ■ 判定 (nKY6 / nKY10)
  13. 指定された能力値分(n個)のダイスを使って判定を行います。
  14. ・nKY6…「有利」を得ていない場合、6面ダイスをn個振って判定します。
  15. ・nKY10…「有利」を得ている場合、10面ダイスをn個振って判定します。
  16. 6もしくは10の出目があればスペシャル。1の出目があればファンブル。
  17. スペシャルとファンブルは同時に発生した場合、両方の処理を行う。
  18. ■ 表
  19. ─ ファンブル表(FT)
  20. ファンブル時の処理を決定します。
  21. ─ 新しい出会いを求める
  22. ─ 一括 新しい出会い表(NMTA) # New Meet Table
  23. その後の表を含めてすべて同時に決定します。
  24. ひとつひとつ振る場合には下記のコマンドを使用してください。
  25. ─ 新しい出会い表(NMT) # New Meet Table
  26. ─ 偶然出会った表(MCT) # Meet by Chance Table
  27. ─ 交流のなかった身近な人表(CIT) # someone Close to you but no Interaction Table
  28. ─ 助けてくれた人表(HYT) # someone Help You table
  29. ─ どんな人だったか表(TLT) # what's They Like Table
  30. ─ 変わった人だった表(EPT) # Eccentric Person Table
  31. ─ ランダム命名表
  32. ─ フルネーム一括生成(FNG) # Full Name Generation
  33. ─ 名字表(LNT) # LastName Table
  34. ─ 名前表(FNT) # FirstName Table
  35. ─ 日本名字表1(JLTO) # Japanese Lastname Table One
  36. ─ 日本名字表2(JLTT) # Japanese Lastname Table Two
  37. ─ カタカナ名字表(FLT) # Foreien Lastname Table
  38. ─ 日本名前表1(JFTO) # Japanese Firstname Table One
  39. ─ 日本名前表2(JFTT) # Japanese Firstname Table Two
  40. ─ カタカナ名前表(FFT) # Foreien Firstname Table
  41. TEXT
  42. 1 register_prefix('\d+KY[6|10]', 'FT', 'NMTA', 'NMT', 'MCT', 'CIT', 'HYT', 'TLT', 'EPT', 'FNG', 'LNT', 'FNT', 'JLTO', 'JLTT', 'FLT', 'JFTO', 'JFTT', 'FFT')
  43. 1 def initialize(command)
  44. 67 super(command)
  45. 67 @sort_barabara_dice = true
  46. 67 @round_type = RoundType::CEIL
  47. end
  48. 1 def eval_game_system_specific_command(command)
  49. 67 then: 16 if /^(\d+)KY(6|10)$/.match(command).nil? != true
  50. 16 else: 51 roll_ky_judge(command)
  51. 51 then: 3 elsif /FT/.match(command).nil? != true && /JFTO|JFTT|FFT/.match(command).nil? == true
  52. 3 else: 48 roll_fumble(command)
  53. 48 then: 21 elsif /NMTA|NMT|MCT|CIT|HYT|TLT|EPT/.match(command).nil? != true
  54. 21 else: 27 generate_new_encounter(command)
  55. 27 then: 27 else: 0 elsif /FNG|LNT|FNT|JLTO|JLTT|FLT|JFTO|JFTT|FFT/.match(command).nil? != true
  56. 27 generate_new_name(command)
  57. end
  58. end
  59. 1 private
  60. 1 def roll_ky_judge(command)
  61. # m[1]にダイス数、m[2]に6/10面がはいる
  62. 16 m = /^(\d+)KY(6|10)$/.match(command)
  63. 16 else: 16 then: 0 unless m
  64. return nil
  65. end
  66. # d6、d10の設定
  67. 16 then: 10 else: 6 n_of_diceside = m[2].to_i == 10 ? 10 : 6
  68. # 振るさいころの数
  69. 16 n_of_rolldice = m[1].to_i
  70. # 成功となる出目
  71. 16 success_dices = [4, 5, 6, 7, 8, 9, 10]
  72. # スペシャルとなる出目
  73. 16 special_dices = [6, 10]
  74. # ファンブルとなる出目
  75. 16 fumble_dices = [1]
  76. # 各種テキストとResultに持っていくための初期値
  77. 16 txt_special = "スペシャル(がんばりが1点上昇!)"
  78. 16 txt_fumble = "ファンブル(ファンブル表:FTを振る)"
  79. 16 txt_success = "成功"
  80. 16 txt_failure = "失敗"
  81. 16 result_txts = []
  82. 16 is_critical = false
  83. 16 is_fumble = false
  84. 16 is_success = false
  85. 16 is_failure = false
  86. # ダイスを振る
  87. 16 dice_list = @randomizer.roll_barabara(n_of_rolldice, n_of_diceside)
  88. # 結果チェック
  89. 16 then: 8 else: 8 is_critical = dice_list.intersection(special_dices).empty? ? false : true
  90. 16 then: 8 else: 8 is_fumble = dice_list.intersection(fumble_dices).empty? ? false : true
  91. 16 then: 4 else: 12 is_success = dice_list.intersection(success_dices).empty? ? false : true
  92. 16 then: 4 else: 12 is_failure = dice_list.intersection(success_dices).empty? ? true : false
  93. # 結果用テキストの生成
  94. 16 then: 12 else: 4 if is_success == true
  95. 12 result_txts.push(txt_success)
  96. end
  97. 16 then: 4 else: 12 if is_failure == true
  98. 4 result_txts.push(txt_failure)
  99. end
  100. 16 then: 8 else: 8 if is_critical == true
  101. 8 result_txts.push(txt_special)
  102. end
  103. 16 then: 8 else: 8 if is_fumble == true
  104. 8 result_txts.push(txt_fumble)
  105. end
  106. 16 return Result.new.tap do |r|
  107. # 最終的に表示するテキスト
  108. 16 r.text = "(#{command}) > [#{dice_list.join(',')}] > #{result_txts.join('・')}"
  109. # 各種パラメータ
  110. 16 r.success = is_success
  111. 16 r.failure = is_failure
  112. 16 r.critical = is_critical
  113. 16 r.fumble = is_fumble
  114. end
  115. end
  116. 1 def roll_fumble(command)
  117. 3 fumbledice = @randomizer.roll_once(6)
  118. 3 fumbletext = FTABLE[fumbledice - 1]
  119. 3 return "ファンブル表(#{command}:#{fumbledice}) > #{fumbletext}"
  120. end
  121. 1 def generate_new_encounter(command)
  122. # 新しい出会い表(一括生成用もいったんまとめて振る)
  123. 21 then: 6 if /NMTA|NMT/.match(command).nil? != true
  124. 6 table0 = NMTABLE
  125. 6 table0dice = @randomizer.roll_once(6)
  126. 6 table0txt = table0[table0dice]
  127. 6 then: 2 if table0dice == 1
  128. 2 table1 = MCTABLE
  129. 2 else: 4 table2 = TLTABLE
  130. 4 then: 0 elsif table0dice == 2
  131. table1 = MCTABLE
  132. else: 4 table2 = EPTABLE
  133. 4 then: 1 elsif table0dice == 3
  134. 1 table1 = CITABLE
  135. 1 else: 3 table2 = TLTABLE
  136. 3 then: 1 elsif table0dice == 4
  137. 1 table1 = CITABLE
  138. 1 else: 2 table2 = EPTABLE
  139. 2 then: 0 elsif table0dice == 5
  140. table1 = HYTABLE
  141. table2 = TLTABLE
  142. else: 2 else
  143. 2 table1 = HYTABLE
  144. 2 table2 = EPTABLE
  145. end
  146. else
  147. else: 15 # その他の表だけ用ダイス
  148. 15 table0dice = @randomizer.roll_once(10)
  149. end
  150. # 新しい出会いを求める際のランダム表個別
  151. 21 then: 3 if /MCT/.match(command).nil? != true
  152. 3 table0 = MCTABLE
  153. 3 else: 18 table0txt = table0[table0dice]
  154. 18 then: 3 elsif /CIT/.match(command).nil? != true
  155. 3 table0 = CITABLE
  156. 3 else: 15 table0txt = table0[table0dice]
  157. 15 then: 3 elsif /HYT/.match(command).nil? != true
  158. 3 table0 = HYTABLE
  159. 3 else: 12 table0txt = table0[table0dice]
  160. 12 then: 3 elsif /TLT/.match(command).nil? != true
  161. 3 table0 = TLTABLE
  162. 3 else: 9 table0txt = table0[table0dice]
  163. 9 then: 3 else: 6 elsif /EPT/.match(command).nil? != true
  164. 3 table0 = EPTABLE
  165. 3 table0txt = table0[table0dice]
  166. end
  167. # 新しい出会い表の一括振り分残りの表決定と結果用テキスト生成
  168. 21 then: 3 if /NMTA/.match(command).nil? != true
  169. 3 table1dice = @randomizer.roll_once(10)
  170. 3 table1txt = table1[table1dice]
  171. 3 table2dice = @randomizer.roll_once(10)
  172. 3 table2txt = table2[table2dice]
  173. 3 resulttxt = "#{table0[0]}(#{table0dice}) > #{table0txt}\n#{table1[0]}(#{table1dice}) > #{table1txt}\n#{table2[0]}(#{table2dice}) > #{table2txt}"
  174. else
  175. else: 18 # 一括じゃない場合は表1枚分なので結果用テキスト生成処理まとめて
  176. 18 resulttxt = "#{table0[0]}(#{table0dice}) > #{table0txt}"
  177. end
  178. 21 return resulttxt
  179. end
  180. 1 def generate_new_name(command)
  181. # 登録したD66のテーブル振るならroll_tables(command, TABLES)
  182. # フルネーム一括生成
  183. 27 then: 3 else: 24 if /FNG/.match(command).nil? != true
  184. 3 nametabledice1 = @randomizer.roll_once(6)
  185. 3 result1 = "#{LNTABLE[0]}(#{nametabledice1}) > #{LNTABLE[nametabledice1]}"
  186. 3 nametabledice2 = @randomizer.roll_once(6)
  187. 3 result2 = "#{FNTABLE[0]}(#{nametabledice2}) > #{FNTABLE[nametabledice2]}"
  188. 3 then: 1 if [1, 2].include?(nametabledice1)
  189. 1 else: 2 result3 = roll_tables("JLTO", TABLES)
  190. 2 then: 1 elsif [3, 4].include?(nametabledice1)
  191. 1 result3 = roll_tables("JLTT", TABLES)
  192. else: 1 else
  193. 1 result3 = roll_tables("FLT", TABLES)
  194. end
  195. 3 then: 1 if [1, 2].include?(nametabledice1)
  196. 1 else: 2 result4 = roll_tables("JFTO", TABLES)
  197. 2 then: 1 elsif [3, 4].include?(nametabledice1)
  198. 1 result4 = roll_tables("JFTT", TABLES)
  199. else: 1 else
  200. 1 result4 = roll_tables("FFT", TABLES)
  201. end
  202. end
  203. # 名字表or名前表(その後の表も振る)
  204. 27 then: 3 if /LNT/.match(command).nil? != true
  205. 3 nametabledice1 = @randomizer.roll_once(6)
  206. 3 result1 = "#{LNTABLE[0]}(#{nametabledice1}) > #{LNTABLE[nametabledice1]}"
  207. 3 then: 1 if [1, 2].include?(nametabledice1)
  208. 1 else: 2 result2 = roll_tables("JLTO", TABLES)
  209. 2 then: 1 elsif [3, 4].include?(nametabledice1)
  210. 1 result2 = roll_tables("JLTT", TABLES)
  211. else: 1 else
  212. 1 result2 = roll_tables("FLT", TABLES)
  213. else: 24 end
  214. 24 then: 3 else: 21 elsif /FNT/.match(command).nil? != true
  215. 3 nametabledice1 = @randomizer.roll_once(6)
  216. 3 result1 = "#{FNTABLE[0]}(#{nametabledice1}) > #{FNTABLE[nametabledice1]}"
  217. 3 then: 1 if [1, 2].include?(nametabledice1)
  218. 1 else: 2 result2 = roll_tables("JFTO", TABLES)
  219. 2 then: 1 elsif [3, 4].include?(nametabledice1)
  220. 1 result2 = roll_tables("JFTT", TABLES)
  221. else: 1 else
  222. 1 result2 = roll_tables("FFT", TABLES)
  223. end
  224. end
  225. # 各表単発
  226. 27 then: 18 else: 9 if /JLTO|JLTT|FLT|JFTO|JFTT|FFT/.match(command).nil? != true
  227. 18 result1 = roll_tables(command, TABLES)
  228. end
  229. # 結果表示用テキスト生成
  230. 27 then: 3 if result4.nil? != true
  231. 3 else: 24 resulttxt = result1 + "\n" + result3 + "\n" + result2 + "\n" + result4
  232. 24 then: 6 elsif result2.nil? != true
  233. 6 resulttxt = result1 + "\n" + result2
  234. else: 18 else
  235. 18 resulttxt = result1
  236. end
  237. 27 return resulttxt
  238. end
  239. # Fumble Table
  240. 1 FTABLE = [
  241. "とんでもない大失敗! 魔法でないと取り返しがつかない! 出目にかかわらず、「魔法の提案」をしない限り判定は失敗になる。",
  242. "もうちょっと何かが足りない。自分の【がんばり】を1点消費することで、出目にかかわらず判定を成功にできる。【がんばり】を消費しなければ出目にかかわらず判定が失敗になる。",
  243. "トラブルが発生したけど「大切な想い」を思い出して何とか乗り切った。大切だと思う世界から学んだこと、大切だと思いたい世界に対する気持ちを思い出して、なんとかしよう。自分の持っているカードの「大切な想い」を1つ選んで〇で囲む。〇で囲めない場合、判定は出目にかかわらず失敗になる。",
  244. "トラブルが発生した。こんな自分を、あの人が見たらどう思うかな。自分が持っているカードに、「大切な想い」を考えて1つ書き込む。",
  245. "トラブルが発生したけど、偶然にも自分の「守りたい人」が助けてくれた。あるいは、「守りたい人」の教えてくれたことが役立った。ありがとう……。",
  246. "ちょっとヒヤリとする瞬間があったけど、何も起こらなかった。よかった。",
  247. ].freeze
  248. # New Meet Table
  249. 1 NMTABLE = [
  250. "新しい出会い表",
  251. "「偶然出会った表(MCT)」と「どんな人だったか表(TLT)」を使用してNPCを作成する。",
  252. "「偶然出会った表(MCT)」と「変わった人だった表(EPT)」を使用してNPCを作成する。",
  253. "「交流のなかった身近な人表(CIT)」と「どんな人だったか表(TLT)」を使用してNPCを作成する。",
  254. "「交流のなかった身近な人表(CIT)」と「変わった人だった表(EPT)」を使用してNPCを作成する。",
  255. "「助けてくれた人表(HYT)」と「どんな人だったか表(TLT)」を使用してNPCを作成する。",
  256. "「助けてくれた人表(HYT)」と「変わった人だった表(EPT)」を使用してNPCを作成する。",
  257. ].freeze
  258. # Meet by Chance Table
  259. 1 MCTABLE = [
  260. "偶然出会った表",
  261. "何らかの事件や事故が起こり、それに巻き込まれた人を助けるために動いた。そのお礼をしたいと声をかけられた。",
  262. "急に振り出した雨。屋根のある所に雨宿りをした際に、同じく雨宿りをしていた人物と話をした。",
  263. "図書館の資料を集めていたところ、偶然にも同じ資料を借りようとしていた人物とバッティングしてしまった。どちらが先にするか話し合った。",
  264. "魔法やオカルトの事を調べるのが趣味らしく、ちょっとした魔法の事件が起こった場所をうろついていた。巻き込まれないように声をかけたら、自分が怪しまれた。",
  265. "街を歩いている時に、うずくまっている人を見つけた。何があったのかと声をかけてみると、何か困っていることがあるらしい。それを助けた。",
  266. "偶然にも稼働していない魔具を見つけたので、回収するために持ち主と話をすることになった。",
  267. "以前、魔具関係の事件で駆け回った時の自分を見かけた人がいたらしい。その時の顔が印象に残ったらしく、何をしていたのか聞かれた。",
  268. "「MAGIA」にたちよったところ、知らない店員がいた。新しく雇ったアルバイトらしく、何をしていたのか聞かれた。",
  269. "たまたま立ち寄った飲食店の店長から、試供品が提供されて、味の感想を求められた。どうやら新メニューを作りたいらしく、いろいろな人の意見を聞いているらしい。",
  270. "「守りたい人」に会いに行ったら、「守りたい人」の親友と名乗る人と出会った。自分の知らない「守りたい人」について話してくれた。",
  271. ].freeze
  272. # someone Close to you but no Interaction Table
  273. 1 CITABLE = [
  274. "交流のなかった身近な人表",
  275. "その人は自分の親戚で、家の用事で出かけたときに親などから紹介をされた。話をしてみたら、自分の興味と同じものを研究していた。",
  276. "親などに頼まれて、ご近所に挨拶へ伺った。その人は近所で見かけることがあったが、不思議と今まで交流がなく、よくわからない人だった。",
  277. "「守りたい人」がたまに話題に出す友人と、「守りたい人」に紹介される形で会う機会ができた。この人はどんな人なのか、見てみよう。",
  278. "きょうだいの知り合いで、挨拶ぐらいはしていたけど、二人きりになったのは初めてだった。きょうだいも用事でいないし、どう話したものか。",
  279. "学業やスポーツの関係で、遠くの国で暮らしていたきょうだい(あるいはいとこ)が帰ってきた。優秀な成績を修めて、世間からも注目されている人物にどう接しようか。",
  280. "昔はずっと一緒に遊んでいた幼馴染だったけど、事情があって最近まで遠くに出かけていた。数日前に帰ってきたらしく、挨拶しにやってきた。",
  281. "「MAGIA」に立ち寄ったところ、店長から話しかけられた。どうも今は暇らしく、話し相手になってほしいとのことだ。",
  282. "SNSなどで知り合い、趣味が合ってネット上の友人となれた人物と、外でも会うことになった。",
  283. "クラスや職場で人気の人が、たまたま一人でいるところを見かけた。向こうもこちらに気づいたらしく、話しかけてきた。さて、どうするかな。",
  284. "趣味の集いに行ったら、クラスメイトや元クラスメイトがいた。趣味の場で会ってみると教室との印象が違った。",
  285. ].freeze
  286. # someone Help You table
  287. 1 HYTABLE = [
  288. "助けてくれた人表",
  289. "忘れ物をしたが、それを届けてくれた。その際に少し話をしたが、優しく丁寧で好感の持てる人だった。",
  290. "自分が転びそうになった、あるいは轢かれそうになった時に、助けてくれた。",
  291. "用事があって普段行かない場所に行ったとき、迷子になった自分を助けてくれた。",
  292. "自分がケガをした子供の対処に困っている時、一緒になって子供の面倒を診てくれた。",
  293. "自分は幼い頃、外でケガをしてしまったことがある。その時に応急処置をして、病院まで運んでくれた人がいる。その人と偶然再会した。",
  294. "自分は幼い頃、何かしらの事情で孤独になり、辛かった時期がある。そんな時に、声をかけて一緒に遊んでくれた人がいた。その人と再会した。",
  295. "自分が不良や話しかけられたくないタイプの人に絡まれた時、声をかけて助けてくれた人がいる。",
  296. "図書館などで資料集めをしている際に、声をかけて助けてくれた人がいた。",
  297. "魔具や財布など重要なものを失くしてしまい、探している必死そうな自分を見て助けてくれた。",
  298. "昔、魔法関係で困った時に、助けてくれた魔法使いがいた。その人が何かの用事で「MAGIA」に立ち寄っており、その時に声をかけた。",
  299. ].freeze
  300. # what's They Like Table
  301. 1 TLTABLE = [
  302. "どんな人だったか表",
  303. "「守りたい人」によく似ている。",
  304. "不良っぽいファッションだけど、単にそういう格好が好きなだけで丁寧な人だった。",
  305. "パリッとした服装、きちんとした身なりで優等生あるいは真面目な人という感じ。",
  306. "活発そうな人物で、スポーツに打ち込んでいそうな体格と口調。いかにも体育会系。",
  307. "サバサバとした性格で、いろいろな人の悩み事を聞いては解決しようとしていた兄貴分(姉貴分)。",
  308. "細かいことが気になるタイプのようで、何かとチェックしてそうな視線を感じた。",
  309. "優しい性格で、自分の言葉を待って聞いてくれる人だった。",
  310. "おしゃべりな人物で、いろいろなことをしゃべってくれる。そのうえで、こちらの話も聞いてくれた。",
  311. "不思議と小動物のような印象を受けた。懐いてきて、自分の反応を楽しみにしているような、そんな人だ。",
  312. "「守りたい人」の知り合いで、共通の知り合いの話題ができた。",
  313. ].freeze
  314. # Eccentric Person Table
  315. 1 EPTABLE = [
  316. "変わった人だった表",
  317. "元気すぎる。声も大きいし、自分は振り回されるし。ちょっと疲れる。",
  318. "優しそうだけど、どこか底知れない、何を考えているのかわからない人物だった。",
  319. "見るからに遊び人で、言動も軽く見える。どこか一定以上親しくなるのを恐れている部分が垣間見えた。",
  320. "ぶっきらぼうで一見とっつきづらい印象だけど、こちらのことをよく見ていて、助けようとしている。たぶん、寂しがり屋。",
  321. "トレンドを着こなしていて、いかにもおしゃれな人だった。ファッションだけでなく、あらゆることを調べて理解しようと動いている。努力の人なんだと思う。",
  322. "自分がその人にとって大事な人に似ているらしく、世話を焼こうとしてくれている。",
  323. "お菓子職人や料理人を目指しているらしく、試食を頼んでくる。",
  324. "誰かを助けなければならない、という理念があり、とにかく人助けをして回っている人だった。自分のことは二の次のようだ。",
  325. "すごい資産家の一族らしく、身に着けている物はすべて高級で、教養もあった。",
  326. "常に何かのアルバイトをしている。掛け持ちだから忙しくしているらしい。",
  327. ].freeze
  328. # LastName Table
  329. 1 LNTABLE = [
  330. "名字表",
  331. "日本名字表1(JLTO)を使用する。",
  332. "日本名字表1(JLTO)を使用する。",
  333. "日本名字表2(JLTT)を使用する。",
  334. "日本名字表2(JLTT)を使用する。",
  335. "カタカナ名字表(FLT)を使用する。",
  336. "カタカナ名字表(FLT)を使用する。",
  337. ].freeze
  338. # FirstName Table
  339. 1 FNTABLE = [
  340. "名前表",
  341. "日本名前表1(JFTO)を使用する。",
  342. "日本名前表1(JFTO)を使用する。",
  343. "日本名前表2(JFTT)を使用する。",
  344. "日本名前表2(JFTT)を使用する。",
  345. "カタカナ名前表(FFT)を使用する。",
  346. "カタカナ名前表(FFT)を使用する。",
  347. ].freeze
  348. TABLES = {
  349. # Japanese Lastname Table One
  350. 1 "JLTO" => DiceTable::D66Table.new(
  351. "日本名字表1",
  352. D66SortType::ASC,
  353. {
  354. 11 => "有栖(ありす)",
  355. 12 => "佐藤(さとう)",
  356. 13 => "鈴木(すずき)",
  357. 14 => "葉月(はづき)",
  358. 15 => "如月(きさらぎ)",
  359. 16 => "皐月(さつき)",
  360. 22 => "九重(ここのえ)",
  361. 23 => "高橋(たかはし)",
  362. 24 => "田中(たなか)",
  363. 25 => "右京(うきょう)",
  364. 26 => "七海(ななみ)",
  365. 33 => "小春(こはる)",
  366. 34 => "伊藤(いとう)",
  367. 35 => "渡辺(わたなべ)",
  368. 36 => "飛鳥(あすか)",
  369. 44 => "渡井(わたらい)",
  370. 45 => "井上(いのうえ)",
  371. 46 => "氷室(ひむろ)",
  372. 55 => "錦(にしき)",
  373. 56 => "柳(やなぎ)",
  374. 66 => "蓬莱(ほうらい)",
  375. }
  376. ),
  377. # Japanese Lastname Table Two
  378. "JLTT" => DiceTable::D66Table.new(
  379. "日本名字表2",
  380. D66SortType::ASC,
  381. {
  382. 11 => "蜂須賀(はちすか)",
  383. 12 => "山本(やまもと)",
  384. 13 => "中村(なかむら)",
  385. 14 => "御影(みかげ)",
  386. 15 => "四季(しき)",
  387. 16 => "常磐(ときわ)",
  388. 22 => "栗栖(くりす)",
  389. 23 => "小林(こばやし)",
  390. 24 => "加藤(かとう)",
  391. 25 => "花野井(はなのい)",
  392. 26 => "綾瀬(あやせ)",
  393. 33 => "乙女(おとめ)",
  394. 34 => "吉田(よしだ)",
  395. 35 => "山田(やまだ)",
  396. 36 => "桐葉(きりは)",
  397. 44 => "桔梗(ききょう)",
  398. 45 => "松本(まつもと)",
  399. 46 => "音羽(おとわ)",
  400. 55 => "蓮見(はすみ)",
  401. 56 => "桜森(さくらもり)",
  402. 66 => "百合園(ゆりぞの)",
  403. }
  404. ),
  405. # Foreien Lastname Table
  406. "FLT" => DiceTable::D66Table.new(
  407. "カタカナ名字表",
  408. D66SortType::ASC,
  409. {
  410. 11 => "レイエス",
  411. 12 => "スミス",
  412. 13 => "ジョンソン",
  413. 14 => "ウィリアム",
  414. 15 => "ブラウン",
  415. 16 => "ジョーンズ",
  416. 22 => "シュルツ",
  417. 23 => "エメリヒ",
  418. 24 => "ファル",
  419. 25 => "クルツ",
  420. 26 => "マイアー",
  421. 33 => "コスキネン",
  422. 34 => "モロー",
  423. 35 => "ルノー",
  424. 36 => "ロベール",
  425. 44 => "ラ",
  426. 45 => "エン",
  427. 46 => "キョウ",
  428. 55 => "ハン",
  429. 56 => "ユン",
  430. 66 => "ホン",
  431. }
  432. ),
  433. # Japanese Firstname Table One
  434. "JFTO" => DiceTable::D66Table.new(
  435. "日本名前表1",
  436. D66SortType::ASC,
  437. {
  438. 11 => "涼太(りょうた)/八重(やえ)",
  439. 12 => "蒼(あおい)/雅(みやび)",
  440. 13 => "樹(いつき)/凛(りん)",
  441. 14 => "蓮(れん)詩(うた)",
  442. 15 => "翔(しょう)/舞(まい)",
  443. 16 => "翼(つばさ)/鈴(すず)",
  444. 22 => "遼(りょう)/瑠華(るか)",
  445. 23 => "陽翔(はると)/結菜(ゆな)",
  446. 24 => "律(りつ)/莉子(りこ)",
  447. 25 => "輝(ひかる)/陽葵(ひまり)",
  448. 26 => "仁(じん)/乃愛(のあ)",
  449. 33 => "大夢(ひろむ)/阿澄(あすみ)",
  450. 34 => "朝陽(あさひ)/結月(ゆづき)",
  451. 35 => "大翔(ひろと)/結愛(ゆあ)",
  452. 36 => "隼人(はやと)/萌花(もか)",
  453. 44 => "公太(こうた)/春歌(はるか)",
  454. 45 => "大和(やまと)/澪(みお)",
  455. 46 => "拓真(たくま)/奈々(なな)",
  456. 55 => "雄大(ゆうだい)/明日香(あすか)",
  457. 56 => "悠(ゆう)/彩(あや)",
  458. 66 => "秀助(しゅうすけ)/那留(なる)",
  459. }
  460. ),
  461. # Japanese Firstname Table Two
  462. "JFTT" => DiceTable::D66Table.new(
  463. "日本名前表2",
  464. D66SortType::ASC,
  465. {
  466. 11 => "一郎(いちろう)/かぐや",
  467. 12 => "太一(たいち)/さくら",
  468. 13 => "颯太(そうた)/あかり",
  469. 14 => "瑛斗(えいと)/こはる",
  470. 15 => "俊輔(しゅんすけ)/ひなた",
  471. 16 => "大地(だいち)/すみれ",
  472. 22 => "健太(けんた)/里奈(りな)",
  473. 23 => "歩(あゆむ)/春菜(はるな)",
  474. 24 => "伊織(いおり)/芽衣(めい)",
  475. 25 => "航(わたる)/愛美(あいみ)",
  476. 26 => "優希(ゆうき)/綾乃(あやの)",
  477. 33 => "直樹(なおき)/茜(あかね)",
  478. 34 => "煌(こう)/もも",
  479. 35 => "陽向(ひなた)/ひかり",
  480. 36 => "将吾(しょうご)/ほのか",
  481. 44 => "和也(かずや)/美穂(みほ)",
  482. 45 => "巧(たくみ)/未来(みらい)",
  483. 46 => "直哉(なおや)/朱里(しゅり)",
  484. 55 => "亮(りょう)/瞳(ひとみ)",
  485. 56 => "陸人(りくと)/心音(ここね)",
  486. 66 => "康平(こうへい)/沙織(さおり)",
  487. }
  488. ),
  489. # Foreien Firstname Table
  490. "FFT" => DiceTable::D66Table.new(
  491. "カタカナ名前表",
  492. D66SortType::ASC,
  493. {
  494. 11 => "カルロ/ビアンカ",
  495. 12 => "リアム/オリビア",
  496. 13 => "イライジャ/エイヴァ",
  497. 14 => "オリバー/ミア",
  498. 15 => "ジェームズ/アメリア",
  499. 16 => "メイソン/シャーロット",
  500. 22 => "オネスト/カルメン",
  501. 23 => "ブルーノ/アンネ",
  502. 24 => "エーミール/クラーラ",
  503. 25 => "ラインハルト/エッダ",
  504. 26 => "テオ/リア",
  505. 33 => "ロメオ/ルチア",
  506. 34 => "セドリック/マリアンヌ",
  507. 35 => "コーム/リーズ",
  508. 36 => "ギー/カトリーヌ",
  509. 44 => "ハオユー/ルーシー",
  510. 45 => "ハオラン/イーラン",
  511. 46 => "イーチェン/シンイー",
  512. 55 => "ウヌ/ハユン",
  513. 56 => "ソジュン/ソア",
  514. 66 => "ジュウォン/スピン",
  515. }
  516. ),
  517. }.freeze
  518. end
  519. end
  520. end

lib/bcdice/game_system/KizunaBullet.rb

100.0% lines covered

100.0% branches covered

79 relevant lines. 79 lines covered and 0 lines missed.
18 total branches, 18 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/kizuna_bullet/tables"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class KizunaBullet < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'KizunaBullet'
  8. # ゲームシステム名
  9. 1 NAME = 'キズナバレット'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'きすなはれつと'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~MESSAGETEXT
  14. ・ダイスロール
  15. nDM…n個の6面ダイスを転がして、一番高い出目を採用します。
  16. ・[調査判定]
  17. nIN…n個の6面ダイスを転がして、一番高い出目が5以上なら成功します。([パートナーのヘルプ]使用可)
  18. ・[鎮静判定]
  19. SEn…2個の6面ダイスを転がして、出目の合計値がn([ヒビワレ]状態の[キズナ]の個数)より高いと成功します。([強制鎮静]使用可)
  20. ・[解決] [アクション]のダメージと[アクシデント]のダメージ軽減
  21. nSO…2+n個の6面ダイスを転がして、出目をすべて合計します。(nは減らした【励起値】。省略可能)
  22. ・各種表
  23. 日常表・場所 OP
  24. 日常表・内容 OC
  25. 日常表・場所と内容 OPC
  26. 日常表(仕事)・場所 OWP
  27. 日常表(仕事)・内容 OWC
  28. 日常表(仕事)・場所と内容 OWPC
  29. 日常表(休暇)・場所 OHP
  30. 日常表(休暇)・内容 OHC
  31. 日常表(休暇)・場所と内容 OHPC
  32. 日常表(出張)・場所 OTP
  33. 日常表(出張)・内容 OTC
  34. 日常表(出張)・場所と内容 OTPC
  35. ターンテーマ表 TT
  36. ターンテーマ表・親密 TTI
  37. ターンテーマ表・クール TTC
  38. ターンテーマ表・主従 TTH
  39. 遭遇表・場所 EP
  40. 遭遇表・登場順 EO
  41. 遭遇表・状況(初対面) EF
  42. 遭遇表・状況(知り合い) EA
  43. 遭遇表・決着 EE
  44. 遭遇表・場所と登場順と状況(初対面)と決着 EFA
  45. 遭遇表・場所と登場順と状況(知り合い)と決着 EAA
  46. 交流表・場所 CP
  47. 交流表・内容 CC
  48. 交流表・場所と内容 CPC
  49. 調査表・ベーシック IB
  50. 調査表・ダイナミック ID
  51. 調査表・ベーシックとダイナミック IBD
  52. ハザード表 HA
  53. 通常ダイジェスト キミたちに新しい命令が下った(調査が依頼された)。
  54. 1:その事件の内容は…… NI1
  55. 2:捜査に向かった場所は…… NI2
  56. 3:犯人のキセキ使いは…… NI3
  57. 4:起きた出来事は…… NI4
  58. 5:バレットの間では…… NI5
  59. 6:戦いの結末は…… NI6
  60. 通常ダイジェスト キミたちは旅行(出張)である場所を訪れた。
  61. 1:その場所とは…… NT1
  62. 2:そこで始まったのは…… NT2
  63. 3:極限状態のなかで…… NT3
  64. 4:犯人のキセキ使いは…… NT4
  65. 5:バレットの間では…… NT5
  66. 6:戦いの結末は…… NT6
  67. ホリデーダイジェスト キミたちは休日に出かけることにした。
  68. 1:その場所とは…… HH1
  69. 2:待ち合わせをしたら…… HH2
  70. 3:そしてなんと…… HH3
  71. 4:ふたりが決めたのは…… HH4
  72. 5:結果的に…… HH5
  73. 6:バレットは最後に…… HH6
  74. ホリデーダイジェスト キミたちは奇妙な事件に出くわした。
  75. 1:その場所とは…… HC1
  76. 2:起きた事件は…… HC2
  77. 3:犯人のキセキ使いは…… HC3
  78. 4:犯人を追い詰めるべく…… HC4
  79. 5:戦いの結果は…… HC5
  80. 6:バレットは最後に…… HC6
  81. MESSAGETEXT
  82. 1 TABLES = translate_tables(@locale)
  83. 1 def initialize(command)
  84. 63 super(command)
  85. 63 @sides_implicit_d = 6
  86. 63 @round_type = RoundType::CEIL
  87. 63 @d66_sort_type = D66SortType::NO_SORT
  88. end
  89. 1 def eval_game_system_specific_command(command)
  90. 63 roll_max(command) || roll_investigate(command) || roll_sedative(command) || roll_solve(command) || roll_tables(command, self.class::TABLES)
  91. end
  92. 1 private
  93. # 最大値
  94. 1 def roll_max(command)
  95. 63 parser = Command::Parser.new("DM", round_type: @round_type)
  96. .has_prefix_number
  97. 63 parsed = parser.parse(command)
  98. 63 else: 1 then: 62 unless parsed
  99. 62 return nil
  100. end
  101. # 最大値計算
  102. 1 dice_list = @randomizer.roll_barabara(parsed.prefix_number, 6)
  103. 1 max = dice_list.max
  104. 1 return Result.new.tap do |r|
  105. # テキストを整形
  106. 1 r.text = "#{command} > [#{dice_list.join(',')}] > #{max}"
  107. end
  108. end
  109. # 調査判定
  110. 1 def roll_investigate(command)
  111. 62 parser = Command::Parser.new("IN", round_type: @round_type)
  112. .has_prefix_number
  113. 62 parsed = parser.parse(command)
  114. 62 else: 3 then: 59 unless parsed
  115. 59 return nil
  116. end
  117. 3 texts = []
  118. 3 is_success = false
  119. 3 is_fumble = false
  120. # 最大値計算
  121. 3 dice_list = @randomizer.roll_barabara(parsed.prefix_number, 6)
  122. 3 max = dice_list.max
  123. 3 if max >= 5
  124. # 5以上の出目があった場合
  125. then: 1 # 成功フラグを立てる
  126. 1 is_success = true
  127. # 成功メッセージを追加
  128. 1 else: 2 texts.push(translate("KizunaBullet.INVESTIGATE.success"))
  129. 2 elsif max >= 3
  130. # 3以上の出目があった場合
  131. then: 1 # 失敗メッセージを追加
  132. 1 texts.push(translate("KizunaBullet.INVESTIGATE.failure"))
  133. # [パートナーのヘルプ]メッセージを追加
  134. 1 texts.push(translate("KizunaBullet.INVESTIGATE.partnerHelp"))
  135. else
  136. # 上記以外
  137. else: 1 # ファンブルフラグを立てる
  138. 1 is_fumble = true
  139. # 失敗メッセージを追加
  140. 1 texts.push(translate("KizunaBullet.INVESTIGATE.failure"))
  141. # ファンブルメッセージを追加
  142. 1 texts.push(translate("KizunaBullet.INVESTIGATE.fumble"))
  143. end
  144. 3 return Result.new.tap do |r|
  145. # テキストを整形
  146. 3 r.text = "#{command} > [#{dice_list.join(',')}] > #{texts.join('')}"
  147. # 各種成否を格納
  148. 3 r.condition = is_success
  149. 3 r.fumble = is_fumble
  150. end
  151. end
  152. # 鎮静判定
  153. 1 def roll_sedative(command)
  154. 59 parser = Command::Parser.new("SE", round_type: @round_type)
  155. .has_suffix_number
  156. 59 parsed = parser.parse(command)
  157. 59 else: 4 then: 55 unless parsed
  158. 55 return nil
  159. end
  160. 4 text = ''
  161. 4 is_success = false
  162. # 合計値計算
  163. 4 sum = @randomizer.roll_sum(2, 6)
  164. 4 if parsed.suffix_number > 12
  165. # 目標値が12より大きい場合
  166. then: 1 # [晶滅]メッセージを追加
  167. 1 else: 3 text = translate("KizunaBullet.SEDATIVE.burst")
  168. 3 elsif parsed.suffix_number < 6
  169. # 目標値が6より小さい場合
  170. then: 1 # [生存]メッセージを追加
  171. 1 else: 2 text = translate("KizunaBullet.SEDATIVE.alive")
  172. 2 elsif sum > parsed.suffix_number
  173. # 合計値が目標値より大きい場合
  174. then: 1 # 成功フラグを立てる
  175. 1 is_success = true
  176. # 成功メッセージを追加
  177. 1 text = translate("KizunaBullet.SEDATIVE.success")
  178. else
  179. # 上記以外
  180. # [強制鎮静]に必要な[キズナ]のチェック数の計算
  181. else: 1 # 目標値と出目の差分を計算
  182. 1 dif = parsed.suffix_number - sum
  183. # チェック一つごとに結果に+2
  184. 1 check = (dif / 2) + 1
  185. # 失敗メッセージを追加
  186. 1 text = translate("KizunaBullet.SEDATIVE.failure", check: check.to_s)
  187. end
  188. 4 return Result.new.tap do |r|
  189. # テキストを整形
  190. 4 r.text = "#{command} > #{sum} > #{text}"
  191. # 各種成否を格納
  192. 4 r.condition = is_success
  193. end
  194. end
  195. # 解決 [アクション]のダメージと[アクシデント]のダメージ軽減
  196. 1 def roll_solve(command)
  197. 55 parser = Command::Parser.new("SO", round_type: @round_type)
  198. .enable_prefix_number
  199. 55 parsed = parser.parse(command)
  200. 55 else: 1 then: 54 unless parsed
  201. 54 return nil
  202. end
  203. # 合計値計算
  204. 1 sum = @randomizer.roll_sum(parsed.prefix_number.to_i + 2, 6)
  205. 1 return Result.new.tap do |r|
  206. # テキストを整形
  207. 1 r.text = "#{command} > #{sum}"
  208. end
  209. end
  210. 1 register_prefix('\d+DM', '\d+IN', 'SE\d+', '\d*SO', TABLES.keys)
  211. end
  212. end
  213. end

lib/bcdice/game_system/KurayamiCrying.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class KurayamiCrying < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'KurayamiCrying'
  7. # ゲームシステム名
  8. 1 NAME = 'クラヤミクライン'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'くらやみくらいん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~TEXT
  13. ・アクシデント表(ACT)
  14. ・感情表(EMO)
  15. ・幕間シーン表(情景)(SST)
  16. ・幕間シーン表(関係)(SRT)
  17. ■ ヨイヤミメビウス
  18. ・大事故イベント表1 日常と正気の破壊(SAE1)
  19. ・大事故イベント表2 アメリカンB級ホラー(SAE2)
  20. ・大事故イベント表3 牙をむく異世界(SAE3)
  21. ・大事故イベント表4 悪意のおとぎ話(SAE4)
  22. ・大事故イベント表5 悲劇の運命(SAE5)
  23. TEXT
  24. 1 def eval_game_system_specific_command(command)
  25. 19 then: 1 if (m = /^ACT(\d+)$/i.match(command))
  26. 1 number = m[1].to_i
  27. 1 return TABLES["ACT"].choice(number).to_s
  28. else: 18 else
  29. 18 roll_tables(command, TABLES)
  30. end
  31. end
  32. TABLES = {
  33. 1 "ACT" => DiceTable::Table.new(
  34. "アクシデント表",
  35. "1D10",
  36. [
  37. "頭の中が黒く染まってゆく、怖い、苦しい。気持ち悪い!でも…なんだか少しだけ、すがすがしい。あなたは「発狂」する。すでに「発狂」している場合、「理性」を2点失う。",
  38. "待って、今のはナシ!調子が愚かったっていうか、ちょっと違うことしちゃったからさ…もう1回やらせてよ、ね?失敗した「判定」を再度やり直す。ただし、前回と同じ「能力値」を使うことはできす、進行役と「交渉」を行った扱いとなる(代替判定により「浸食」が2点増加する)。",
  39. "こっちは必死にやってるってのに、まったく、アイツめ……! あなたが「ツナガリ」を結んでいる主人公を任意に1人選び、「感情」を変更する。この際、必す「負の惑情」を選ばなければならない。「ツナガリ」を結んでいる主人公がいない場合、ダイスを振り直し、再度「アクシデント表」に当てはめる。",
  40. "不意を突かれたあなたは、とっさに化物を攻撃する!……確かに化物に見えたのだ。しかし、あなたが手にかけたのは見知った顔だった。あなたが正の「ツナガリ」を結んでいる主人公をランダムに1人選び、2点のダメージを与える。正の「ツナガリ」を結んでいる主人公がいない場合、ダイスを振り直し、再度「アクシデント表」に当てはめる。",
  41. "さっきからずっと、不気味な視線を感じる……どうやら、良くない存在に目をつけられてしまったようだ。「怪異」があなたに一方的な「ツナガリ」を獲得する。すでに「怪異」から「ツナガリ」を獲得されている場合、ダイスを振り直し、再度「アクシデント表」に当てはめる。",
  42. "ぶつんと頭の中で音がする。あれっ?誰かのことを考えていたような……なんだか記憶が霞んで、思い出せない。あなたが獲得している「ツナガリ」をランダムに1つ失う(「継続的なツナガリ」である場合、セッション終了後に再度獲得する)。「ツナガリ」が1つもない場合、ダイスを振り直し、再度「アクシデント表」に当てはめる。",
  43. "ぞわりと背中に懇寒が走る。自分を取り巻く「流れ」──運命に似た何かが歪んでしまったような、おぞましい予感が胸を走る。「確保」しているダイスの目が「10」になる。ダイスを「確保」していない場合、新たに「10」を「確保」する。すでに「10」の目を「確保」している場合、ダイスを振り直し、再度「アクシデント表」に当てはめる。",
  44. "違う……違う、違う。これは自分のせいじゃない。いや、きっと何かの間違いだ。そう、あいつのせいに決まってる!進行役があなた以外の主人公をランダムに1人選ぶ(誰を選んだか参加者に教えてはならない) 。選ばれた主人公が次に判定を行った際、進行役は、最も低い数字を示しているダイスの目を「10」に変更する。",
  45. "あぁ……見つからない。アレがないとダメなのに。一体どうしたら──!「アイテム」をランダムに1つ失う(「継続品」である場合、センョン終了後に再度獲得する)。「アイテム」を1つも所持していない場合、「アイテム」を所持する主人公をランダムに1人選び、2点のダメージを与え、「アイテム」を1つ奪い取る。主人公が誰も「アイテム」を所持していない場合、「理性」を2点失う。",
  46. "まるで自分を支える何かが失われたように、あなたはその場に立ち尽くす。諦めと絶望が心を支配する。ああ、そうか。これが、「心が折れる」ということか……。あなたは「理性」を4点失う。"
  47. ]
  48. ),
  49. "EMO" => DiceTable::Table.new(
  50. "感情表",
  51. "1D10",
  52. [
  53. "(正)信頼/(負)依存",
  54. "(正)安心/(負)不安",
  55. "(正)友情/(負)憤怒",
  56. "(正)尊敬/(負)恐怖",
  57. "(正)愛情/(負)嫉妬",
  58. "(正)共感/(負)否定",
  59. "(正)忠誠/(負)侮蔑",
  60. "(正)憧憬/(負)劣等感",
  61. "(正)性愛/(負)拒絶",
  62. "(正)狂信/(負)殺意",
  63. ]
  64. ),
  65. "SST" => DiceTable::Table.new(
  66. "幕間シーン表(情景)",
  67. "1D10",
  68. [
  69. "先が見えない闇の中を、あなたは手探りに進んでいる。暗がりに入り込んでしまったのか、それとも辺りの光が消えたのか———その時、あなたの眼前に、闇から溶け出すように何者かの姿が現れた。",
  70. "夢を見ていた。かつてあった出来事が、目の前で繰り返される……ハッと気が付き、現実に戻る。心配そうにあなたを覗き込む顔を見て、再び夢の光景がフラッシュバックする。この人、あの時の……!",
  71. "気が付くと見知らぬ場所を1人歩いている。迷ってしまったのだろうか。辺りを見回していた、その時———あなたは背後に気配を感じた。いつの間にか誰か立っている……!",
  72. "「危ない!」突然上がった声と同時に、あなたは突き飛ばされ、床を転がった。次の瞬間、不気味で巨大な何かがあなたの頭をかすめてゆく……。あなたは身を起こし、あなたと一緒に倒れ込んだ人物に声をかけた。",
  73. "不気味な声を上げながら、何かがゆっくりと近づいてくる。あなたが咄嗟に身を隠した場所には、すでに誰かいた。このまま息を殺し、一緒に危険が過ぎ去るのを待つしかない。",
  74. "むせかえるような臭いが辺りに満ちている。これは血の臭いだろうか。いや、それにしては……。すると、あなたの近くで、誰かが小さく咳き込んだ……",
  75. "一息つけそうな場所を見つけ、あなたは座りこんだ。不気味なことに巻き込まれているとは思えない、穏やかな時間が流れる。ふと、あなたは隣りに座っている人物に話しかけた。",
  76. "静寂の中、あなたを呼ぶ声が響く。声の主に対し、あなたは思う。望むところだ。自分の方こそ、確認しなければならないことがある———!あなたは足早に、声のする方へと進んだ。",
  77. "高い場所に立ち、あなたは異常な世界を見下ろしている。その時、後ろで誰かが地面を踏む音がした。来たか……予想通り、ここでなら会うことができた。あなたは振り返り、相手を見た。",
  78. "周囲を確認し、あなたは相手に合図を送る。足音静かに、相手があなたの元へと駆け寄る。———他の気配はない。慎重に、密やかに、あなたは相手と話し始めた。",
  79. ]
  80. ),
  81. "SRT" => DiceTable::Table.new(
  82. "幕間シーン表(関係)",
  83. "1D10",
  84. [
  85. "微かな香り。ちょっとした仕事。横顔。あの人のすべてが、あなたの胸を高鳴らせる———こんな気持ちは、初めてだ。",
  86. "頭の中にノイズが走る。あなたは、たしかに、あの人とあったことがある。けれど、詳しく思い出そうとするたびに頭痛が走る……この記憶、確かめなければ。",
  87. "異常な事態だというのに……いや、異常な事態だからこそ、あの人はあなたに安心感を与えてくれる、とにかく話がしたい。今はまず、あの人を探そう。",
  88. "今あなたに必要なのは「捨て駒」だ。そう、ピッタリの奴がいるじゃないか!誰を犠牲にしても生き残ってやる。そのためには……。あなたは、あの人の方へと歩み寄った。",
  89. "こんな時でも、どこか気の合う相手というのは見つかるものだ———安堵するような、弾むような気持ちで、あなたはその人に声をかけた。さぁ、共闘といこうじゃないか。",
  90. "なんでよりによってこんなヤツと……!?図らずも二人きりになってしまった相手に、あなたは眉をひそめた。会話はない。そもそもこいつが安全かわからない……誰か助けて!",
  91. "特に理由はない。けれど、一緒に行動すること自体は大事でしょう?仕方ないじゃないか、怖いんだから……!あなたは、いそいそと手近な人間へと寄って行った。",
  92. "不意に昔のこと———二度と取り戻せない過ちが頭をよぎる。そんなことを思い出したのも、あの人の面影を、あの顔に感じてしまうせいだ。別人とはわかっている。けれど、今度こそ———。",
  93. "あなたは影に隠れ、その人物を見張っている。怪しい……この人こそが、事件の元凶じゃないか?とはいえ、このままではじり貧だ。あなたは意を決し、影から飛び出して話をかけた。",
  94. "間違いない……!あなたはその人物をにらみつけた。何という幸運だろう。追い求めた相手が、すぐそこにいるなんて!あなたは荒れ狂う胸の内を気取られぬよう、ゆっくりと近づいた。",
  95. ]
  96. ),
  97. "SAE1" => DiceTable::Table.new(
  98. "大事故イベント表1 日常と正気の破壊",
  99. "1D10",
  100. [
  101. "非日常に慣れてしまう自分が恐ろしい。心が恐怖を感じなくなってきたみたいだ……。セッション終了まで【精神】が2点減少する。",
  102. "最悪の展開を予測する。死よりも恐ろしいことになるのは明白だ。あなたは理性を2点失う。",
  103. "被害者の成れの果てを目撃し、絶望する。いやだ、こんな風になりたくない……!あなたは次に判定をする際、目標値が2点増加する。",
  104. "日常の記憶が恐怖に支配されてゆく。友人も、家族も、家も街も、きっと呑み込まれてしまうんだ……。セッション終了まで「継続的なツナガリ」を1つ失う。「継続的なツナガリ」がない場合は理性を2点失う。",
  105. "異世界の謎を解き明かす手掛かりを見つける。読み解くのはあまりに難解だが……人であることをやめれば、あるいは。理性を2点失い『真相』を1枚確認する。『真相』がない、あるいは確認できない状況である場合はダイスを振りなおす。",
  106. "体の色が変わり、力が入らなくなってゆく……元に戻れないのでは、と思いゾッとする。セッション終了まで【肉体】が2点減少する。",
  107. "異世界に染まる──なぜ、これほど簡単な逃げ道に気付かなかったのだろう。あなたは即座に発狂する。既に発狂していた場合は理性を2点失う。",
  108. "この世界の背後にある物語、あるいは、破滅者に同情してしまう。戦わねばならない時、こぶしをふるうことはできるだろうか……。戦闘時、あなたの最初のラウンドでの行動のみ進行役が決定する。",
  109. "侵蝕は思った以上に深刻だ。自分とは、何だったか。自分は本当に自分なのか……。セッション終了まで【頭脳】が2点減少する。",
  110. "勘違いしていた。あいつも、こいつも、みんな敵だ。自分を陥れようとしているんだ……!セッション終了まで「援護」をすることができなくなる(この状態は「失調」として扱う)。",
  111. ]
  112. ),
  113. "SAE2" => DiceTable::Table.new(
  114. "大事故イベント表2 アメリカンB級ホラー",
  115. "1D10",
  116. [
  117. "諦めかけたその時、過去に戦ったあいつらが俺の拳に乗り移る。お前ら……力を貸してくれ!以降、一度だけ自分の攻撃に〔ダイス2つ分〕点の追加ダメージを得る。「過去に戦ったあいつら」は好きに捏造してよい。",
  118. "運命の人に出会う。こんなところでなければ、もっと幸せだったのに。あなたはツナガリを獲得する。対象は他の主人公や登場人物でも、今回のセッションに登場していないキャラクターでも構わない。また、破滅判定において目標値が2点減少する。",
  119. "死んだと思っていたあいつが生きて帰ってきた。これは奇跡だ!あなたはツナガリを獲得する。対象はセッションに登場していないキャラクターにする。また、あなたは戦闘中、常に2点の追加ダメージを得る。",
  120. "唐突に銃撃戦が始まった!!!Wow!!あなたに流れ弾が直撃し、4点のダメージを受ける。ただし、それっぽいアメリカンな演技で無事を主張できれば、このダメージをなかったことにできる。",
  121. "何故かはわからないが、あなたが行動するたびに、どこからかアメリカンなリアクションが聞こえてくる。どうにも、集中力がそがれる……セッション終了まで、全ての判定の目標値が1点増加する(破滅判定を除く)。この効果は重複する。",
  122. "唐突に、ポップな曲が辺り一帯に流れる。これは一体?主人公は全員、次に判定を行う際、アメリカンな行動をとった場合に目標値が1点増加する(破滅判定の場合は1点減少する)。アメリカンかどうかの判断は進行役に委ねられる。なお、曲に乗って踊りながら行動する演出にした場合は、判定の目標値がさらに1点増加する。",
  123. "些細なことが気になり、他の主人公に対し声を荒げてしまう。そんなことをしてもどうにもならないと、わかっているのに……。あなたがツナガリを獲得している主人公を一人選び、相手とのツナガリを失う。ただし、ハグして仲直りする演出を行うなら、ツナガリを消さなくともよい。",
  124. "要するに全部やっつけちまえばいい、そういう事だろ?脳内で声がする。そうだ、銃は全てを解決する!ダイスを1つ振り、出た目の数だけ「武器」を獲得する。ただし同じ数だけ、破滅判定の際の目標値が増加する。",
  125. "気が付くと、顔や体格が変化している!㈰イケメン ㈪ブロンド ㈫タフガイ ㈬ブレインのどれかを選択する。㈰は全ての能力値が1点増加する。㈪は【精神】、㈫は【肉体】、㈬は【頭脳】が2点増加する。ただし㈰〜㈬は全て、破滅判定の目標値が2点増加する。",
  126. "最後の一言を言い残し、あなたのキャラクターは絶命する。全米が号泣する感動のシーンだ。あなたは進行役が許可する範囲で、あなたの主人公の最期を自由に演出する。ただし、主人公は異世界の影響ですぐに復活する。侵蝕を〔ダイス2つ分〕点増加させる(最大10点)。",
  127. ]
  128. ),
  129. "SAE3" => DiceTable::Table.new(
  130. "大事故イベント表3 牙をむく異世界",
  131. "1D10",
  132. [
  133. "異世界からの侵蝕の影響か、あなたの姿が乳児になり、全ての「能力値」を「失調」する(いずれかの「能力値」が「復調」した場合、姿は元に戻る)。",
  134. "こんなところにいられるか!こいつらといたら命がいくつあっても足りない!あなたは、一人になろうとする。次の「選択」の結果、あなたが一人になることができなかった場合、あなたの理性は半分になる。(端数切り上げ)",
  135. "何かはわからないが、あなたはこの異世界の住人の逆鱗に触れてしまったようだ。あなたに対して、誰かが「負の感情」で「ツナガリ」を結ぶ(誰が結ぶかは進行役が決定すること)。",
  136. "運に見放された?主人公全員の「確保」しているダイスを捨て、新たに全員が「10」の目のダイスを「確保」する。",
  137. "セッション終了まで、あなたが外来語を口にするたびに、あなたの主人公の「侵蝕」が1点増加する。",
  138. "あなたには、周囲の人間全てがおぞましい怪物に見える。以降セッション終了まで、他の主人公が同じ場面にいる場合、判定に使用するダイスが一個減少する。",
  139. "あなたの外見がおぞましい怪物へと変化する。こんな姿では、人とかかわることができない!他の主人公があなたに結んでいる「ツナガリ」がすべて失われる(「継続的なツナガリ」を除く)。",
  140. "主人公全員の外見が、いずれかの主人公と同じになる。次の「選択」が行われるまで(戦闘中であればそのラウンドが終了するまで)全ての能力値がその主人公の数値と同じになる。進行役は、どの主人公の姿に変化するか決定すること。",
  141. "主人公たちは、お互いの姿を見ることができなくなる。次の「選択」が行われるまで(戦闘中であればそのラウンドが終了するまで)主人公は全員、自分以外の主人公にアイテムを使用することができなくなる。",
  142. "あなたの姿が老人になる。全ての能力値が4点減少し、また全ての「ツナガリ」を忘れてしまう(「ツナガリ」は消えないが「援護」や感情の変更を行うことができなくなる)。この状態は「失調」として扱い「薬」や「治療」の効果により元に戻る。また新たな「ツナガリ」を獲得した場合も姿は元に戻る。",
  143. ]
  144. ),
  145. "SAE4" => DiceTable::Table.new(
  146. "大事故イベント表4 悪意のおとぎ話",
  147. "1D10",
  148. [
  149. "何か尖ったものに触れてしまった。途端に、あなたは強烈な眠気に襲われた……。あなたが次に幕間作成を行う場合「休憩」(『トコヤミメイズ』P74)しか選ぶことができない。",
  150. "誰かが倒れ、息絶えている……いや、あれは自分だ。自分自身の、未来の姿なのか……?あなたが平静状態であれば発狂する。すでに発狂していれば侵蝕が4点増加する。",
  151. "突然の爆音。あなたの脇を、スポーツカーがドリフトしながら駆け抜けてゆく。なにあれかっこいい!「穢れ:最後の執着」(『クラヤミクライン』P180)の効果をあなたに適用する。",
  152. "別の異世界から来たという情報屋に出会う。情報屋は、今回の怪異のレベルを教え、どこかへと去る。侵蝕が4点増加する。",
  153. "狐の嫁入り行列が目の前を遮る。狐は主人公たちに、毛皮をモフモフさせてくれる。幸せだ!……が、気が付くと、ふところが軽くなっている。主人公は全員、アイテムをランダムに一つ失う。",
  154. "怪異(または破滅者)がシレッと横にいる。あなたの見たもの聞いたもの触れたものに興味があるようだ。今回登場する怪異(または破滅者)の存在点が〔ダイス1つ分〕増加する。",
  155. "ボロボロの日記帳が、開かれた状態で落ちている。すると、日記帳に「ヤブッタページヲカエシテ!」と文字が浮かび上がった。あなたはアイテム「運命の日記」(『トコヤミメイズ』P73)を入手する。代わりに、破滅判定時、自分に向けられている「負の感情」一つにつき侵蝕が4点増加する。",
  156. "エイリアンにアブダクションされる。あなたは突然、このシーンから消え去る。以降、幕間で「メイン」として指定されるか「終章」に入るまでゲームに登場することができない。なお、再登場した際は呆けた表情で戻ってくる。",
  157. "悪魔と契約をしてしまった。以降、あなたは判定で出した「10」のダイス目をいくつでも「確保」できる。ただし「確保」した「10」のダイス目は「1」との相殺以外で消すことができない。",
  158. "あなたは足元に現れた泉に落ちる。泉からはい上がると、あなたの頭の中に3人のあなたがいる。頭の中がうるさくて落ち着かない!以後、判定の際にダイスを一つ追加し、最も低い出目の一つはなかったことにする。",
  159. ]
  160. ),
  161. "SAE5" => DiceTable::Table.new(
  162. "大事故イベント表5 悲劇の運命",
  163. "1D10",
  164. [
  165. "シナリオに直接関係ないが、あなたの家が燃える。",
  166. "シナリオに直接関係ないが、あなたの口座残高が0になる。クレジットカードも使用不可能になる。",
  167. "シナリオに直接関係ないが、会社から解雇される。自身が会社員ではない場合は経営している店や実家が倒産したり、持っている株が暴落したりする。",
  168. "シナリオに直接関係ないが、あなたの親の訃報、もしくは大切な何かが喪失した連絡を受ける。本当かどうかは、現実に生還するまでわからない。",
  169. "シナリオに直接関係ないが、あなたは突然〔ダイス2つ分〕歳を取る(能力値に変動は発生しない)。",
  170. "シナリオに直接関係ないが、あなたが原因で大事故、もしくは大災害が発生する。損害賠償で数億〜数十億程度の借金を負う。",
  171. "シナリオに直接関係ないが、病魔により余命幾ばくも無いことを悟ってしまう。",
  172. "シナリオに直接関係ないが、あなたはSNSで大炎上する。マスコミにも実名報道され、今後大変な生活を送ることになる。",
  173. "シナリオに直接関係ないが、この場で突然子供が誕生する。主人公役は名前や性別を決めること。なお、何らかの原因により子供が命を落とした場合、理性を10点失う。",
  174. "進行役は主人公役に何か一つ質問をする。その質問に対し可能な限り正直に答えなければならない(公序良俗に反する質問やハラスメントにあたる質問であった場合を除く)。",
  175. ]
  176. ),
  177. }.freeze
  178. 1 register_prefix(TABLES.keys)
  179. end
  180. end
  181. end

lib/bcdice/game_system/Kutulu.rb

100.0% lines covered

90.0% branches covered

44 relevant lines. 44 lines covered and 0 lines missed.
10 total branches, 9 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Kutulu < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Kutulu'
  7. # ゲームシステム名
  8. 1 NAME = 'Kutulu'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'くとうるう'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGETEXT
  13. ■判定 nKU n: ダイス数
  14. 例)3KU: ダイスを3個振って、その結果を表示(ギリギリでの成功も表示)
  15. ■対抗判定 nKR n: ダイス数
  16. 例)2KR: ダイスを2個振って、その結果を表示。対抗判定用の3桁の数字も出力。(大きい方が勝利)
  17. INFO_MESSAGETEXT
  18. 1 register_prefix('\dK[UR]')
  19. 1 def initialize(command)
  20. 15 super(command)
  21. 15 @sort_barabara_dice = true # バラバラロール(Bコマンド)でソート有
  22. end
  23. 1 def eval_game_system_specific_command(command)
  24. 15 resolute_action(command) || resolute_competition(command)
  25. end
  26. 1 private
  27. # アクティヴ能力の判定
  28. # @param [String] command
  29. # @return [Result]
  30. 1 def resolute_action(command)
  31. 15 m = /(\d)KU/.match(command)
  32. 15 else: 10 then: 5 return nil unless m
  33. 10 num_dices = m[1].to_i
  34. 10 dices = @randomizer.roll_barabara(num_dices, 6).sort
  35. 10 dice_text = dices.join(",")
  36. 10 output = "(#{num_dices}KU) > #{dice_text}"
  37. 41 success_num = dices.count { |val| val >= 4 }
  38. 10 counts_4 = dices.count(4)
  39. 10 then: 9 if success_num > 0
  40. 9 output += " > 成功数#{success_num}"
  41. 9 then: 2 else: 7 if success_num == 1 && counts_4 == 1
  42. 2 output += " > *ギリギリでの成功"
  43. end
  44. 9 return Result.success(output)
  45. else: 1 else
  46. 1 output += " > 失敗"
  47. 1 return Result.failure(output)
  48. end
  49. end
  50. # 対抗判定用出力
  51. # @param [String] command
  52. # @return [Result]
  53. 1 def resolute_competition(command)
  54. 5 m = /(\d)KR/.match(command)
  55. 5 else: 5 then: 0 return nil unless m
  56. 5 num_dices = m[1].to_i
  57. 5 dices = @randomizer.roll_barabara(num_dices, 6).sort
  58. 5 dice_text = dices.join(",")
  59. 5 counts_6 = dices.count(6)
  60. 5 counts_5 = dices.count(5)
  61. 19 success_num = dices.count { |val| val >= 4 }
  62. 5 com_text = format("(%d%d%d)", success_num, counts_6, counts_5)
  63. 5 output = "(#{num_dices}KR) > #{dice_text} > #{com_text}"
  64. 5 then: 4 if success_num > 0
  65. 4 return Result.success(output)
  66. else: 1 else
  67. 1 return Result.failure(output)
  68. end
  69. end
  70. end
  71. end
  72. end

lib/bcdice/game_system/KyokoShinshoku.rb

98.78% lines covered

98.0% branches covered

82 relevant lines. 81 lines covered and 1 lines missed.
50 total branches, 49 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class KyokoShinshoku < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "KyokoShinshoku"
  7. # ゲームシステム名
  8. 1 NAME = "虚構侵蝕TRPG"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "きよこうしんしよくTRPG"
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定
  14.  ダイスを指定数ダイスロールして、最も高い出目を出力します。難易度を指定すると成否を判定します。オプションでA、Dをつけると、[有利][不利]の条件で振れます(A=[有利]、D=[不利])。
  15. KS(x,y)
  16. x:ダイスサイズ。1=D4(能力値1、2以上の出目が出ていたとしても最大1)/2=D4(能力値2、3以上の出目が出ていたとしても最大2)/3=D4(能力値3、出目4が出ていたとしても最大3)/4=D4/6=D6/8=D8/10=D10/12=D12/20=D20
  17. y:ダイス数(省略:1)
  18. KS(x,y)>=z
  19. x:ダイスサイズ。1=D4(能力値1、2以上の出目が出ていたとしても最大1)/2=D4(能力値2、3以上の出目が出ていたとしても最大2)/3=D4(能力値3、出目4が出ていたとしても最大3)/4=D4/6=D6/8=D8/10=D10/12=D12/20=D20
  20. y:ダイス数(省略:1)
  21. z:難易度
  22. KS(x,y)A>=z([有利]:KS(x,y)の判定を2回行い、それぞれの結果のより大きい方が結果となります)
  23. x:ダイスサイズ。1=D4(能力値1、2以上の出目が出ていたとしても最大1)/2=D4(能力値2、3以上の出目が出ていたとしても最大2)/3=D4(能力値3、出目4が出ていたとしても最大3)/4=D4/6=D6/8=D8/10=D10/12=D12/20=D20
  24. y:ダイス数(省略:1)
  25. z:難易度
  26. KS(x,y)D>=z([不利]:KS(x,y)の判定を2回行い、それぞれの結果のより小さい方が結果となります)
  27. x:ダイスサイズ。1=D4(能力値1、2以上の出目が出ていたとしても最大1)/2=D4(能力値2、3以上の出目が出ていたとしても最大2)/3=D4(能力値3、出目4が出ていたとしても最大3)/4=D4/6=D6/8=D8/10=D10/12=D12/20=D20
  28. y:ダイス数(省略:1)
  29. z:難易度
  30. ・観測ロール
  31.  [現実乖離]の段階に応じたダイスを指定数ダイスロールして、最も高い出目を出力します。
  32. KR(x)
  33. x=[現実乖離]の段階(1=D4/2=D6/3=D8/4=D10/5=D12/6=D20)
  34. KR(x,y) 観測ロール(リアリティラインあり)
  35. x=[現実乖離]の段階(1=D4/2=D6/3=D8/4=D10/5=D12/6=D20)
  36. y=[リアリティライン]のレベル(3=1個/2=2個/1=3個)
  37. ・虚構の収束の侵蝕度減少ロール
  38.  [現実乖離]の段階に応じたダイスを指定数ダイスロールして、その合計を出力します。
  39. KRS(x,y)
  40. x=[現実乖離]の段階(1=D4/2=D6/3=D8/4=D10/5=D12/6=D20)
  41. y=ダイスの個数
  42. MESSAGETEXT
  43. 1 register_prefix('KS', 'KR', 'KRS')
  44. 1 def eval_game_system_specific_command(command)
  45. 66 roll_check(command) || roll_kansoku(command) || roll_shusoku(command)
  46. end
  47. 1 private
  48. 1 DICE_SIZE_TO_SIDES = {
  49. 1 => 4,
  50. 2 => 4,
  51. 3 => 4,
  52. 4 => 4,
  53. 6 => 6,
  54. 8 => 8,
  55. 10 => 10,
  56. 12 => 12,
  57. 20 => 20,
  58. }.freeze
  59. 1 def roll_check(command)
  60. 66 m = /^KS(?:\(([-+\d]+),([-+\d]+)?\)|(\d+))([AD]?)(?:>=([-+\d]+))?$/.match(command)
  61. 66 else: 48 then: 18 return nil unless m
  62. 48 then: 46 else: 2 dice_size = m[1] ? Arithmetic.eval(m[1], @round_type) : Arithmetic.eval(m[3], @round_type).to_i
  63. 48 then: 44 else: 4 times = m[2] ? Arithmetic.eval(m[2], @round_type) : 1
  64. 48 target = m[5] && Arithmetic.eval(m[5], @round_type)
  65. 48 advantage = m[4]
  66. 48 sides = DICE_SIZE_TO_SIDES[dice_size]
  67. 48 then: 1 else: 47 return nil if sides.nil? || times.nil?
  68. 112 then: 29 else: 18 rolls = Array.new(advantage.empty? ? 1 : 2) { roll_check_once(times, dice_size, sides) }
  69. 112 values = rolls.map { |v| v[:value] }
  70. value =
  71. 47 then: 13 if advantage == "A"
  72. 13 else: 34 values.max
  73. 34 then: 5 elsif advantage == "D"
  74. 5 values.min
  75. else: 29 else
  76. 29 values.first
  77. end
  78. result =
  79. 47 then: 7 if value == 1
  80. 7 else: 40 Result.fumble("ファンブル")
  81. 40 then: 6 elsif target && value < target
  82. 6 else: 34 Result.failure("失敗")
  83. 34 then: 5 elsif target && value == sides
  84. 5 else: 29 Result.critical("クリティカル")
  85. 29 then: 5 elsif target && value >= target
  86. 5 Result.success("成功")
  87. else: 24 else
  88. 24 Result.new()
  89. end
  90. 47 result.text = [
  91. 47 then: 19 else: 28 target ? "(KS(#{dice_size},#{times})#{advantage}>=#{target})" : "(KS(#{dice_size},#{times})#{advantage})",
  92. format_rolls(rolls),
  93. value,
  94. result.text,
  95. ].compact.join(" > ")
  96. 47 return result
  97. end
  98. 1 def roll_check_once(times, dice_size, sides)
  99. 65 then: 21 if times < 1
  100. 21 dice_list = @randomizer.roll_barabara(2, sides).sort
  101. 21 value = dice_list.min.clamp(1, dice_size)
  102. else: 44 else
  103. 44 dice_list = @randomizer.roll_barabara(times, sides).sort
  104. 44 value = dice_list.max.clamp(1, dice_size)
  105. end
  106. 65 return {dice_list: dice_list, value: value}
  107. end
  108. 1 def format_rolls(rolls)
  109. 47 then: 4 else: 43 if rolls.length == 1 && rolls.first[:dice_list].length == 1
  110. 4 return nil
  111. end
  112. 43 rolls.map do |v|
  113. 61 then: 4 else: 57 v[:dice_list].length == 1 ? v[:value].to_s : "#{v[:value]}[#{v[:dice_list].join(',')}]"
  114. end.join(", ")
  115. end
  116. 1 GENJITU_KAIRI_TO_SIDES = [4, 6, 8, 10, 12, 20].freeze
  117. 1 REALITY_LINE_TO_TIMES = {
  118. 3 => 1,
  119. 2 => 2,
  120. 1 => 3,
  121. }.freeze
  122. 1 def roll_kansoku(command)
  123. 19 m = /^KR(?:(\d+)|\((\d),(\d)\))$/.match(command)
  124. 19 else: 10 then: 9 return nil unless m
  125. 10 then: 7 else: 3 dice_size = m[1]&.to_i || m[2].to_i
  126. 10 then: 3 else: 7 reality_line = m[3]&.to_i
  127. 10 then: 0 else: 10 if reality_line && (reality_line > 3 || reality_line < 1)
  128. return nil
  129. end
  130. 10 sides = GENJITU_KAIRI_TO_SIDES[dice_size - 1]
  131. 10 times = REALITY_LINE_TO_TIMES[reality_line] || 1
  132. 10 else: 9 then: 1 return nil unless sides
  133. 9 dice_list = @randomizer.roll_barabara(times, sides).sort
  134. 9 value = dice_list.max
  135. 9 then: 3 else: 6 cmd = reality_line ? "KR(#{dice_size},#{reality_line})" : "KR(#{dice_size})"
  136. 9 then: 7 if times == 1
  137. 7 "(#{cmd}) > #{value}"
  138. else: 2 else
  139. 2 "(#{cmd}) > #{value}[#{dice_list.join(',')}] > #{value}"
  140. end
  141. end
  142. 1 def roll_shusoku(command)
  143. 10 m = /^KRS(?:\((\d),([-+\d]+)\))$/.match(command)
  144. 10 else: 8 then: 2 return nil unless m
  145. 8 dice_size = m[1].to_i
  146. 8 times = m[2] && Arithmetic.eval(m[2], @round_type)
  147. 8 sides = GENJITU_KAIRI_TO_SIDES[dice_size - 1]
  148. 8 then: 1 else: 7 return nil if sides.nil? || times.nil?
  149. 7 dice_list = @randomizer.roll_barabara(times, sides)
  150. 7 value = dice_list.sum
  151. 7 then: 6 if times == 1
  152. 6 "(KRS(#{dice_size},#{times})) > #{value}"
  153. else: 1 else
  154. 1 "(KRS(#{dice_size},#{times})) > #{value}[#{dice_list.join(',')}] > #{value}"
  155. end
  156. end
  157. end
  158. end
  159. end

lib/bcdice/game_system/Liminal.rb

90.91% lines covered

80.77% branches covered

66 relevant lines. 60 lines covered and 6 lines missed.
26 total branches, 21 branches covered and 5 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Liminal < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Liminal'
  7. # ゲームシステム名
  8. 1 NAME = 'リミナル'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'りみなる'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGETEXT
  13. ■技能判定 LMx+b>=t+m x:技能レベル b:ボーナス t:難易度 m:敵の技能レベル(対抗判定)
  14. 例)LM2>=8: 技能レベル2,難易度8で技能判定し、その結果を表示。(クリティカル成功も表示)
  15. LM3+2>=9:技能レベル3,ボーナス+2,難易度9で技能判定し、その結果を表示。( 〃 )
  16. LM0>=8: 技能なし,難易度8で技能判定する。(難易度+2は自動的に足されます)
  17. ■イニシアティヴ判定 LIx+b>=t+m x:認識力レベル b:ボーナス t:難易度 m:敵の認識力レベル
  18. 例)LI2>=8+2: 認識力レベル2,難易度8,敵認識力レベル2で技能判定し、その結果を表示。
  19. LI0>=8+2: 認識力なし,難易度8,敵認識力レベル2で技能判定する。(難易度加算なし)
  20. INFO_MESSAGETEXT
  21. 1 register_prefix("LI", "LM")
  22. 1 def eval_game_system_specific_command(command)
  23. 10 resolute_action(command) || resolute_initiative(command)
  24. end
  25. 1 private
  26. # 技能判定
  27. # @param [String] command
  28. # @return [Result]
  29. 1 def resolute_action(command)
  30. 10 parser = Command::Parser.new("LM", round_type: @round_type)
  31. .has_suffix_number
  32. .restrict_cmp_op_to(:>=)
  33. 10 parsed = parser.parse(command)
  34. 10 else: 7 then: 3 return nil unless parsed
  35. 7 skill_level = parsed.suffix_number
  36. 7 bonus = parsed.modify_number
  37. 7 difficulty = parsed.target_number
  38. 7 dice = @randomizer.roll_barabara(2, 6)
  39. 7 dice_total = dice.sum
  40. 7 total = dice_total + skill_level + bonus
  41. 7 then: 1 else: 6 difficulty += 2 if skill_level == 0
  42. 7 return Result.new.tap do |result|
  43. 7 result.condition = (total >= difficulty)
  44. 7 result.critical = (total >= difficulty + 5)
  45. 7 then: 2 else: 5 if dice_total == 2
  46. 2 result.fumble = true
  47. 2 result.critical = false
  48. 2 result.condition = false
  49. end
  50. sequence = [
  51. 7 "(LM#{skill_level}#{with_symbol(bonus)}>=#{difficulty})",
  52. "#{dice_total}[#{dice.join(',')}]#{with_symbol(skill_level + bonus)}",
  53. total.to_s,
  54. 7 then: 2 if result.fumble?
  55. 2 else: 5 "1ゾロ"
  56. 5 then: 1 elsif result.critical?
  57. 1 "クリティカル"
  58. else: 4 else
  59. 4 then: 2 else: 2 result.success? ? "成功" : "失敗"
  60. end
  61. ].compact
  62. 7 result.text = sequence.join(" > ")
  63. end
  64. end
  65. 1 def with_symbol(number)
  66. 16 then: 9 if number == 0
  67. 9 else: 7 return "+0"
  68. 7 then: 7 elsif number > 0
  69. 7 return "+#{number}"
  70. else: 0 else
  71. return number.to_s
  72. end
  73. end
  74. # イニシアティヴ判定
  75. # @param [String] command
  76. # @return [Result]
  77. 1 def resolute_initiative(command)
  78. 3 parser = Command::Parser.new("LI", round_type: @round_type)
  79. .has_suffix_number
  80. .restrict_cmp_op_to(:>=)
  81. 3 parsed = parser.parse(command)
  82. 3 else: 1 then: 2 return nil unless parsed
  83. 1 skill_level = parsed.suffix_number
  84. 1 bonus = parsed.modify_number
  85. 1 difficulty = parsed.target_number
  86. 1 dice = @randomizer.roll_barabara(2, 6)
  87. 1 dice_total = dice.sum
  88. 1 total = dice_total + skill_level + bonus
  89. 1 return Result.new.tap do |result|
  90. 1 result.condition = (total >= difficulty)
  91. 1 result.critical = (total >= difficulty + 5)
  92. 1 then: 0 else: 1 if dice_total == 2
  93. result.fumble = true
  94. result.critical = false
  95. result.condition = false
  96. end
  97. sequence = [
  98. 1 "(LI#{skill_level}#{with_symbol(bonus)}>=#{difficulty})",
  99. "#{dice_total}[#{dice.join(',')}]#{with_symbol(skill_level + bonus)}",
  100. total.to_s,
  101. 1 then: 0 if result.fumble?
  102. else: 1 "1ゾロ"
  103. 1 then: 0 elsif result.critical?
  104. "クリティカル"
  105. else: 1 else
  106. 1 then: 1 else: 0 result.success? ? "成功" : "失敗"
  107. end
  108. ].compact
  109. 1 result.text = sequence.join(" > ")
  110. end
  111. end
  112. end
  113. end
  114. end

lib/bcdice/game_system/LiveraDoll.rb

97.44% lines covered

75.0% branches covered

39 relevant lines. 38 lines covered and 1 lines missed.
12 total branches, 9 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class LiveraDoll < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'LiveraDoll'
  7. # ゲームシステム名
  8. 1 NAME = '紫縞のリヴラドール'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ししまのりうらとおる'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. アタックX:[x]ATK(BNo)
  14. []内のコマンドは省略可能。
  15. 「x」でダイス数を指定。省略時は「1」。
  16. (BNo)でブロックナンバーを指定。「236」のように記述。順不同可。
  17. 【書式例】
  18. ・4ATK263 → 4dでブロックナンバー「2,3,6」の判定。
  19. ----------------------------------------------------------------
  20. 以下のコマンドは、リヴラデッキカードの補助を目的としたものです。
  21. 使用の際は上部メニューより
  22. 「カード → カード配置の初期化 → 紫縞のリヴラドール:リヴラデッキ」
  23. と操作し、リヴラデッキを使用できる状態にしておいてください。
  24. 各リヴラデッキカードの末尾に書かれている [] 内のコマンドをタイプすると、
  25. カード名と効果のテキストを参照できます。
  26. コマンドは【色】【ネイル種別】【管理番号】の3要素で構成されており、
  27. それぞれ、以下の文字が対応しています。
  28. 【色】
  29. C:無 K:黒 W:白 R:赤 B:青 G:緑 E:ライヴラリアン
  30. 【ネイル種別】
  31. L:リヴラネイル D:パッシヴドレス O:オーナーズネイル
  32. 例:CL1(無色のリヴラネイルの1番目『ストライク』)
  33. 例:KD2(黒のパッシヴドレスの2番目『第二夜の黒』)
  34. 例:WO3(白のオーナーズネイルの3番目『罪なき純白』)
  35. MESSAGETEXT
  36. 1 register_prefix('(\d+)?ATK')
  37. 1 def initialize(command)
  38. 26 super(command)
  39. 26 @sort_add_dice = true
  40. 26 @sort_barabara_dice = true
  41. end
  42. 1 def eval_game_system_specific_command(command)
  43. 26 check_roll(command) || card_text(command)
  44. end
  45. 1 private
  46. 1 def check_roll(command)
  47. 26 m = /^(\d+)?ATK([1-6]{0,6})$/.match(command)
  48. 26 else: 8 then: 18 return nil unless m
  49. 8 then: 6 else: 2 dice_count = m[1]&.to_i || 1
  50. 8 block_no = m[2].each_char.map(&:to_i).sort.uniq
  51. 8 dice_array = @randomizer.roll_barabara(dice_count, 6).sort
  52. 34 then: 16 else: 10 result_array = dice_array.map { |n| block_no.include?(n) ? "×" : n }
  53. 34 success = result_array.count { |n| n.is_a?(Integer) }
  54. 8 dice_text = dice_array.join(",")
  55. 8 block_text = block_no.join(',')
  56. 8 result_text = result_array.join(',')
  57. 8 return "#{dice_count}D6(Block:#{block_text}) > #{dice_text} > #{result_text} > 成功数:#{success}"
  58. end
  59. 1 def card_text(command)
  60. 18 m = /^([CKWRBGE][LDO])(\d+)$/.match(command)
  61. 18 else: 18 then: 0 return nil unless m
  62. 18 deck_type = m[1]
  63. 18 card_index = m[2].to_i
  64. 18 then: 0 else: 18 if card_index == 0
  65. return nil
  66. end
  67. 18 deck = DECKS[deck_type]
  68. 18 else: 18 then: 0 return nil unless deck
  69. 18 deck[card_index - 1]
  70. end
  71. DECKS = {
  72. 1 'CL' => [
  73. '『ストライク』 対象に【アタック:1《OD》】を行い、可能ならば追加で【エクストルード】を行う(可能な状況であれば行わなければならない)。',
  74. '『シュート』 対象に【アタック:1《OD》】を行う。対象が自身より低い「高度」に存在する場合、代わりに【アタック:2《OD》】を行う。',
  75. '『スナイプ』 対象に【アタック:1《OD》】を行う。対象が自身より低い「高度」に存在する場合、代わりに【アタック:2《OD》】を行う。',
  76. '『ウォーク』 【ムーヴ:1】を行う。',
  77. '『ラン』 【ムーヴ:2】を行う。',
  78. '『オルタネート』 直後に行うアタックネイルでは、ダイスロールを2度行い、任意の一方の結果を選ぶことが出来る。',
  79. '『ジャンプ』 このアタックネイル終了時まで自身が「高度:3《OD》」に存在するものとして扱う。',
  80. '『オーヴァードライヴ』 直後のネイルでは《OD》指定された数値を「4《OD》」増加する。',
  81. '『ガード』 ダイスロールで使用されたダイスの内ふたつまでを選ぶ。その出目を1減少する。',
  82. '『パリィ』 ダイスロールで使用されたダイスの内ふたつまでを選ぶ。そのダイスを振り直しさせる。この時、振り直した後の値のみを採用する。',
  83. '『カウンターアタック』 自身の「シールドレス」を破壊したユニットに対し、即座に【アタック:1】を行う。',
  84. '『トラップ』 移動を行ったユニットに対し、即座に【アタック:1】を行う。',
  85. '『ミスチーフ』 移動を行ったユニットに、追加で【ムーヴ:1】を行わせる。この移動先は貴女が決定する。',
  86. '『ライトニングダンス』 即座に【ムーヴ:1】を行う。(これによって、直後のアタックネイルの射程の外に出た場合、そのアタックネイルのダイスロールは行われず、失敗したことになる)',
  87. ],
  88. 'CD' => [
  89. '『貴女好みの装い(おすきなように)』 貴女好みの装いは破壊されない。',
  90. '『迷子の貴女へ(きめられないのなら、そのままどうぞ)』 全ての色(無色を含む)のAsレベルが3であるかのようにオーナーズネイルを使用することが出来る。',
  91. ],
  92. 'KL' => [
  93. '『黒爪の掻きむしり(デザイア・スクラッチ)』 対象に【アタック:黒Asレベル《OD》+1】を行う。',
  94. '『黒爪の突き刺し(ヘイトレッド・ピアース)』 対象に【アタック:3《OD》】を行い、その後【エクストルード】を行ってもよい。',
  95. '『黒弾の豪雨(ブラックレイン・ダムネイション)』 対象に【アタック:4】を行う。その後自身に【アタック:1】を行う。',
  96. '『黒弾の奔流(ブラックニードルカスケイド)』 対象に【アタック:2】を行う。対象が自身よりも低い「高度」に存在する場合、代わりに【アタック:4《OD》】を行う。',
  97. '『黒影の疾走(シャドウ・ストリート・ラン)』 【ムーヴ:1】か【ムーヴ:2】のどちらかを行う。',
  98. '『夜空を征け(ナイト・ランナー)』 【ムーヴ:1】を行う。このムーヴネイル以降、クリンナップフェイズ終了時まで、自身が「高度:7」に存在するものとして扱う。',
  99. '『黒刃の執行者(ブラック・エンフォーサー)』 直後に行うアタックネイルでは、《OD》指定された数値を「2《OD》」増加する。また、2以上の成功数が出た場合、攻撃対象の「シールドレス」を追加でもう1枚破壊する。',
  100. '『黒茨の塔を駆け抜けよ(スーサイド・ドライヴ)』 自身に【アタック:1】を行う。これ以降クリンナップフェイズ終了時まで、地震が「高度:13《OD》」に存在するものとして扱う。',
  101. '『舞い踊る黒刃(ハイマニューバ・ブラック・ブレイド)』 直前のムーヴネイルで移動したセル数に等しい回数だけ、直後のアタックネイルの複製を作成し、実行する。',
  102. '『影跳び(シャドウ・ダッジ)』 直前のアタックネイルによって、自身の「シールドレス」が1枚も破壊されていなかった場合、即座に【ドロゥ:1】を行う。',
  103. '『報復の刃(アヴェンジャー・エッジ)』 自身の「シールドレス」を破壊したユニットに対し、即座に【アタック:黒Asレベル】を行う。',
  104. ],
  105. 'KD' => [
  106. '『始まりの黒(ニューブラック・ドレス)』',
  107. '『第二夜の黒(クレセントブラック・ドレス)』 自身がドロゥを行う時、自身に【アタック:1】を行うことで、ドロゥ数を+2しても良い。',
  108. '『第三夜の黒(ハーフブラック・ドレス)』 自身がドロゥを行う時、ダイスロールを行うダイスのうちひとつを振らず、任意の出目を出したものとして良い。',
  109. '『第四夜の黒(フルブラック・ドレス)』 いずれかのユニットがムーヴネイルを使用する度、そのユニットに対し即座に【アタック:2】を行ってもよい。',
  110. '『終わりの黒(ダークブラック・ドレス)』 自身を含む全てのユニットの、ドロゥフェイズ中のドロゥ数を5減少する。',
  111. ],
  112. 'KO' => [
  113. '『意志の介入(マインド・ランペイジ)』 プレイヤーの1人を対象とする。対象のオーナーズネイルをすべて見る。その後、その中のひとつを「使用済」にする。',
  114. '『意志の散逸(マインド・ロスト)』 ドロゥのダイスロールに使用されたダイスひとつを取り除く。(取り除かれたダイスはセットダイスとしてセットされない)',
  115. '『漆黒の願い(ブラック・ウィッシュ)』 このラウンドの終了時まで、自身の黒のコスト上限を3増加する。(例えば、現在の黒のAsレベルが2である場合、このラウンドの間のみAsレベルが5であるかのようにオーナーズネイルを使用することが出来る。ただし、実際にAsレベルが上昇しているわけではないことに注意すること)',
  116. '『想いの黒刃(ハートブレイド:ブラック)』 ユニット1体を対象とする。対象に【アタック:3】を行い、自身のリヴラドールに【アタック:1】を行う。',
  117. '『黒の報酬(ブラック・サプライズ)』 自身のリヴラドールに【アタック:1】を行う。このフェイズで行う自身のドロゥ数を2増加する。',
  118. '『翔けよ黒夜(ミッドナイトホーク)』 このラウンド終了時まで、貴女のリヴラドールが使用するアタックネイルに以下の一文を追加する。「対象が自身よりも低い「高度」に存在する場合、追加で【アタック:1】を行う。」',
  119. '『傷跡の共鳴(ハート・レゾナンス)』 プレイヤー1人を対象とする。対象の「シールドレス」を1枚破壊する。その後自身の「シールドレス」を1枚破壊する。',
  120. '『居心地の悪さ(ブラック・マイアズマ)』 このムーヴネイルを打ち消す。',
  121. '『鉄茨よ侵食せよ(ブラックブランブル)』 セルひとつを指定する。指定したセルに「鉄茨マーカー」を設置する。',
  122. '『鉄華乱舞(アイアン・ブルーム)』 ユニット1体を対象とする。対象に【アタック:3】を行う。これによって対象の「シールドレス」を1枚以上破壊した場合、対象のセットダイスの内、貴女の任意のふたつを取り除く。',
  123. '『だむねいしょん』 自身のリヴラドールを含む、ナインライヴラリ上に存在する全てのユニットの現在の「パッシヴドレス」を1枚破壊する。(現在のパッシヴドレスの前に装備していたパッシヴドレスへと変更される)',
  124. '『残酷な真実(クルーエルトゥルース)』 リヴラオーナー1人を対象とする。対象のオーナーズネイルをすべて見る。その後、その中のみっつを「使用済」にする。',
  125. '『孤独と銃と最前線(アヴァンドナー)』 これ以降自身のリヴラが行うムーヴネイル全てに以下の一文を追加する。「移動先のセルに存在するユニットに対し【アタック:1】を行っても良い」。これはリヴラバトル終了時まで継続する。',
  126. '『節制の黒絢(テンパランス:ザ ブラックソード)』 自身のオーナーズネイルの内、任意のふたつの「使用済」を解除する。',
  127. '『雷電の黒絢(ライトニング:ザ ブラックソード)』 ユニット1体を対象とする。対象に【アタック:2】を行う。これによって対象の「シールドレス」を1枚以上破壊した場合、さらに対象のセットダイスを1個取り除く。',
  128. '『思索の黒絢(マインド:ザ ブラックソード)』 全てのプレイヤーはプレイヤー自身のセットダイスを1個取り除く。その後貴女は【ドロゥ:2】を行う。',
  129. '『爛熱の黒絢(グロウス:ザ ブラックソード)』 全てのプレイヤーは【ドロゥ:1】を行う。その後、貴女は【ドロゥ:2】を行う。',
  130. ],
  131. 'WL' => [
  132. '『閃け白刃(ホワイトブレイド)』 対象に【アタック:白Asレベル《OD》+1】を行い、その後【エクストルード】を行ってもよい。',
  133. '『二重に響け白刃(ホワイト・ダブルストライク)』 対象に【アタック:1】を行い、その後【アタック:1】を行う。',
  134. '『白き弾丸にて狙い撃て(ホワイト・スナイパー)』 対象に【アタック:2】を行う。対象が自身よりも低い「高度」に存在する場合、代わりに【アタック:4《OD》】を行う。',
  135. '『白き弾丸よ降り注げ(ホワイト・バレットシャワー)』 対象に【アタック:3《OD》】を行い、続けて【アタック:3】を行う。',
  136. '『白光の如く駆けよ(フラッシュ・ランニング)』 【ムーヴ:3】を行う。',
  137. '『閃光の突撃(フラッシュチャージ)』 対象が存在するセルへ移動する。',
  138. '『白光の衣(ホワイト・エンチャント)』 直後のアタックネイルで、現在の自身の「シールドレス」の枚数以上の成功数が出た場合、自身の「シールドレス」を1枚回復する。',
  139. '『荘厳なりし白の塔(ホワイトゴールドタワー)』 クリンナップフェイズ終了時まで、自身が「高度:8《OD》」に存在するものとして扱う。',
  140. '『輝きの盾(ホワイトシールド)』 自身のパッシヴドレスの「ブロックナンバー」に6を追加する。この効果はこのダイスロールの結果のみに有効である。',
  141. '『より疾きは光の一手(ライトニング・インターセプト)』 移動を行ったユニットに対し、即座に【アタック:2】を行う。',
  142. '『白の語り部(ホワイトテラー)』 ダイスロールで使用されたダイス全ての出目を6に変更する。',
  143. ],
  144. 'WD' => [
  145. '『愚者の白(ホワイトフール)』',
  146. '『魔術師の白(ホワイトマジシャン)』 自身が「高度:6」以上に存在する時、ドロゥ数を+1しても良い。',
  147. '『女教皇の白(ホワイトハイプリエステス)』 1ラウンドに1回まで、自身のダイスロールの出目ひとつを1増加しても良い。',
  148. '『女帝の白(ホワイトエンプレス)』 自身の白のアタックネイルに、以下の一文を追加する。「続けて【アタック:1】を行う。射程はこのアタックネイルに準ずる」',
  149. '『皇帝の白(ホワイトエンペラー)』 自身の「シールドレス」が破壊される度に、1d6のダイスロールを行う。この時1か2の出目が出た場合「シールドレス」を1枚回復する。',
  150. ],
  151. 'WO' => [
  152. '『秩序の護り手(ホワイト・ディフェンダー)』 【ドロゥ:1】を行う。',
  153. '『あなたにも愛を(トゥーミーユアラヴリィ)』 自身の「シールドレス」を1枚回復し、その後自身以外の「シールドレス」を1枚回復する。',
  154. '『罪なき純白(じゅんぱくイノセント)』 このドロゥフェイズで行うダイスロールの出目を全て1減少する。(1の出目は1のままである)',
  155. '『白銀に輝け我が左腕(アージェティア)』 このアタックネイルで「シールドレス」を少なくとも1枚以上破壊した場合、追加で【アタック:2】を行う。',
  156. '『撲滅の白(パニッシュメント・ブレス)』 自身のリヴラドールを含む、ナインライヴラリ上に存在する全てのユニットに【アタック:2】を行う。',
  157. '『誠実の白(ホワイトオネスティ)』 次のスタンバイフェイズ開始時まで、自身のリヴラドールのパッシヴドレス「ブロックナンバー」に5を追加する。',
  158. '『正義の剣(ソード・オブ・ジャスティス)』 このアタックネイルで「シールドレス」を少なくとも2枚以上破壊した場合、自身の「シールドレス」を1枚回復する。',
  159. '『物語の護り手(ロア・ディフェンダー)』 ナインライヴラリ上に存在するマーカーを、任意の数取り除く。',
  160. '『撲滅の賦(がらすまどのむこうがわ)』 自身のリヴラドールを含む、ナインライヴラリ上に存在する全てのユニットの現在の「パッシヴドレス」を1枚破壊する。(現在のパッシヴドレスの前に装備していたパッシヴドレスへと変更される)',
  161. '『忘却の白(ホワイト・オブリビオン)』 自身のセットダイスを全て取り除く。自身のオーナーズネイルの内、任意のふたつの「使用済」を解除する。',
  162. '『白の従者(ホワイト・フォロワ)』 セルひとつを指定する。指定したセルに「白従者マーカー」を設置する。',
  163. '『秩序の龍(クロム・クラーク・レプリカ)』 セルひとつを指定する。指定したセルに「偽龍マーカー」を設置する。',
  164. '『夢の向こうの旅人(ロアテラ)』 このドロゥフェイズで行うダイスロールでは、ダイスそれぞれに対し、任意の出目が出たものとして扱う。',
  165. '『混色もまた物語:黒(ロア:ブラック)』 自身を含む全てのユニットに【アタック:4】を行う。',
  166. '『混色もまた物語:赤(ロア:レッド)』 ユニット1体を対象とする。対象に【アタック:ラウンド数】を行う。このアタックで「シールドレス」を破壊した場合、貴女の「シールドレス」を1枚回復する。',
  167. '『混色もまた物語:青(ロア:ブルー)』 使用されたオーナーズネイルの効果は発揮されず、「使用済」となる。',
  168. '『混色もまた物語:緑(ロア:グリーン)』 プレイヤー1人を対象とする。対象の「シールドレス」を1枚回復する。',
  169. ],
  170. 'RL' => [
  171. '『焼きつくせ炎の爪(ファイアクロウ)』 対象に【アタック:赤Asレベル《OD》+2】を行う。',
  172. '『焦がれの情熱(ファイアフィスト)』 対象に【アタック:4】を行い、その後追加で【エクストルード】を行っても良い。',
  173. '『掻きむしれ炎禍(ファイアドライヴ)』 対象に【アタック:赤Asレベル】を行い、その後【エクストルード】を行う。移動先は対象ごとに、貴女が決定する。',
  174. '『炎の壁よなぎ払え(ファイアウォール)』 自身の存在するセルと、隣接しているセル全てに存在するユニット全て(自身を除く)を対象とする。対象に【アタック:2】を行う。',
  175. '『赤熱鉄柱ぶん回しの刑(マス・ファイア・ブレード)』 対象に【アタック:4】を行い、続けて【アタック:3《OD》】を行う。その後【エクストルード】を2度行う。',
  176. '『赤熱溶断ぶった斬り(ヒュージ・ファイア・ブレード)』 対象に【アタック:3《OD》】を行い、続けて【アタック:2】を行い、続けて【アタック:1】を行う。',
  177. '『追い打ちの炎渦(ファイアストーム)』 直後に行うアタックネイルでは、《OD》指定された数値を「3」増加する。また、このアタックネイルで「シールドレス」を1枚以上破壊した場合、即座に【ドロゥ:2】を行い、続けてセットダイスを2個取り除く。',
  178. '『雷電疾走(ライトニング・ランニング)』 【ムーヴ:3】を行う。',
  179. '『烈火流星雨あられ(メテオストーム)』 このムーヴネイルに以下の一文を追加する。「このムーヴネイルの移動開始セル、通過したセル、移動完了セルに存在する全てのユニット(自身を含む)に【アタック:3】を行う」',
  180. '『あなたは私のもの!(にがさない)』 移動を行ったユニットを、自身と同じセルまで移動させる。',
  181. '『叩き落とせ!(フォールアウト)』 アタックネイルを使用するユニット1体を対象とする。対象が存在するセルの高度を0に変更する。また対象の「高度」をクリンナップフェイズまで、即座に0に変更する。',
  182. ],
  183. 'RD' => [
  184. '『灯散らす赤き花輪(フローラルリング)』 リヴラフェイズ開始時に、任意のユニット1体を対象とし【アタック:1】を行ってもよい。',
  185. '『アネモスのビスチェ』 ドロウフェイズ時、自身のドロゥ数を1減少することで、自身を除く全てのユニットに【アタック:1】を行うことを選んでも良い。',
  186. '『ベラドンナのピンヒール』 自身の行う【アタック:X】では、攻撃対象のブロックナンバーのうち「2」を無視して攻撃を行うことが出来る。',
  187. '『オダマキの花冠(フラワークラウン)』 クリンナップフェイズの開始時に、自身を除く全てのユニットに【アタック:2】を行う。',
  188. '『朱塔の花園(ブルーミングガーデン)』 メインフェイズ開始時、自身の「シールドレス」を1枚破壊しても良い。こうした場合、オーナーズネイルひとつの「使用済」を解除する。',
  189. ],
  190. 'RO' => [
  191. '『走れ雷電(ライトニング・ボルト)』 ユニット1体を対象とし、【アタック:2】を行う。全てのプレイヤーは、このオーナイズネイルに対し、リアクトネイルを使用することが出来ない。',
  192. '『穿て炎槍(フレイムランス)』 ユニット1体を対象とし、【アタック:2】を行う。全てのプレイヤーは、このオーナイズネイルに対し、リアクトネイルを使用することが出来ない。',
  193. '『熱情と踊れ(ダンス・ウィズ・ヒート)』 自身のリヴラドールを含む全てのユニットに対し【アタック:1】を行う。',
  194. '『昇炎の罠(ファイアリングトラップ)』 直後のムーヴネイルで移動を行ったユニットを対象とし、【アタック:3】を行う。',
  195. '『精神混沌の炎(レッド・パラノイア)』 自身のセットダイスのうち、任意のふたつを取り除き、【ドロゥ:2】を行う。セットダイスがふたつ以上存在しない場合にはこのネイルを使用することが出来ない。',
  196. '『愛情の渇望(あなたがほしい)』 任意のユニット1体を対象とする。対象を自身と同じセルに移動させる。その後自身と同じセルに存在するユニット全てに【アタック:2】を行う。',
  197. '『過去からの想い(6400年後の私へ)』 このドロゥフェイズで貴女はドロゥを行うことが出来ない。次のラウンドのドロゥフェイズでは、貴女のドロゥ数を7増加する。',
  198. '『咲き乱れよ百合の花(レッド・リリィ)』 自身を含む全てのユニットが行ったドロゥのダイスロール結果全てを振り直させる。',
  199. '『煉獄の恋(ヘルフレイム・ラヴソング)』 プレイヤー1人を対象とする。対象の「シールドレス」を1枚破壊する。その後自身の「シールドレス」を1枚破壊する。',
  200. '『その信頼は重圧(トラストユー)』 ユニット1体を対象とする。このラウンドの終了時まで、対象がいずれかのユニットに【アタック:X】を行う度に、対象に【アタック:1】を行う。',
  201. '『龍炎の嵐(ドラゴンストーム)』 セルひとつを指定する。指定したセルに「炎龍マーカー」を設置する。',
  202. '『復讐の花(ブルーム・オブ・リベンジ)』 自身のリヴラドールを除く全てのユニットに【アタック:4】を行い、続けて【アタック:3】を行う。',
  203. '『再臨の銀(アガートラム)』 このドロゥフェイズで行った自身のダイスロール結果のダイス全ての出目を3減少する。その後【ドロゥ:3】を行う(このドロゥには出目減少の効果は適用されない)。',
  204. '『銀腕、携えるは黒(フレイガラク:ブラック)』 自身のセットダイスを2個取り除く。ユニット1体を対象とする。対象に【アタック:3】を行い、【アタック:2】を行い、【アタック:1】を行う。',
  205. '『銀腕、携えるは白(クライドハームソルース:ホワイト)』 全てのユニットの「シールドレス」を1枚回復する。その後貴女はさらに「シールドレス」を1枚回復する。',
  206. '『銀腕、携えるは青(カレトヴルッフ:ブルー)』 【ドロゥ:5】を行う。その後セットダイスを2個取り除く。',
  207. '『銀腕、携えるは緑(スカザック:グリーン)』 セルひとつを指定する。指定したセルに「影槍マーカー」を設置する。',
  208. ],
  209. 'BL' => [
  210. '『碧空の剣(ストラトスフィア・ブレイド)』 対象に【アタック:3】を行う。',
  211. '『蒼天の剣靴(ストラトスフィア・ブレイドブーツ)』 対象に【アタック:1】を行う。対象が自身よりも低い「高度」に存在する場合、代わりに【アタック:4《OD》】を行い、対象の存在するセルへ移動する。',
  212. '『強襲翼撃(ウィング・ブレイド)』 対象に【アタック:3《OD》】を行い、対象の存在するセルへ移動する。',
  213. '『蒼弓の猛撃(ブルー・アローレイン)』 対象に【アタック:1】を行う。対象が自身よりも低い「高度」に存在する場合、続けて【アタック:3】を行う。',
  214. '『空歩き(エアステップ)』 【ムーヴ:2】を行う。このムーヴネイル以降、クリンナップフェイズ終了時まで、自身が「高度:6《OD》」に存在するものとして扱う。',
  215. '『凪歩き(カームステップ)』 【ムーヴ:1】を行う。移動先のセルにリヴラドールが存在する場合、【エクストルード】を行っても良い。',
  216. '『風の道標(ウィンドサインポスト)』 このアタックネイルの効果で「シールドレス」を1枚以上破壊した場合、アタックネイルの処理が終わった後、【ドロゥ:1】を行う。',
  217. '『精密思考(シャープセンス)』 このアタックネイルでは、攻撃対象のブロックナンバーのうち「3」を無視して攻撃を行うことが出来る。',
  218. '『思考の渦(ぐるぐる)』 ダイスロールに使用されたダイスひとつを指定する。そのダイスを振り直させる。',
  219. '『空翔けの回避(レビテート)』 そのアタックネイルのダイスロールで使用されたダイス全ての出目を1減少する。',
  220. '『たゆたう心、空の様に(ストラトスフィア・ハート)』 自身に適用された【エクストルード】を打ち消し、元のセルへと戻る。その後【ドロゥ:1】を行う。',
  221. ],
  222. 'BD' => [
  223. '『青空を這い(スカイ・クロウラ)』 セットアップフェイズ毎に、ダイスを1個振っても良い。そうした場合、クリンナップフェイズまで、ダイスの出目に等しい「高度」に自身が存在するものとして扱う。',
  224. '『碧海を舞い(ブルー・アルペジオ)』 自身が「高度:0」にいる間、ドロゥ数を2増加する。',
  225. '『蒼天を翔ける(キディ・グレイド)』 ドロゥフェイズでのドロゥ数を1減少することで、即座に任意のユニット1体に【アタック:1】を行っても良い。この効果は1ラウンドに1回のみ宣言出来る。',
  226. '『戦場の妖精(フェアリィドレス:スノウ・ウィンド)』 自身が「高度:6」以上に存在する間、自身のブロックナンバーに6を追加する。',
  227. '『いつか碧空の果てへ(プレアデス)』 自身がドロゥを行う時、ダイスロールに使用するダイスの内最大2個を任意の出目が出たことにして良い。',
  228. ],
  229. 'BO' => [
  230. '『冷静な思案(いま、このタイミング)』 【ドロゥ:青Asレベル】を行う。',
  231. '『入念な思考(これとこれは、いらないかな)』 【ドロゥ:1】を行い、セットダイスから任意のひとつを取り除く。',
  232. '『即決即断(みてたよ。させないんだから)』 このダイスロールのダイス目全てを2減少する。',
  233. '『方針変更(こっちの方がきっといいよ)』 ダイスロールで使用されたダイスひとつを裏返す(もしくは7からその出目の数値を引いた出目に変更する)。',
  234. '『小さな知略(マハトマ)』 任意のプレイヤー1人を対象とする。対象のオーナーズネイルを見る。その中から1枚を指定する。対象はそのオーナーズネイルを次のラウンドのクリンナップフェイズまで使用できなくなる。',
  235. '『青の精鋭(ブルー・アデプト)』 セットダイスを2個取り除く。ユニット1体を対象とする。対象に【アタック:2】を行う。',
  236. '『対抗(カウンタースペル)』 使用されたオーナーズネイルの効果は発揮されず、「使用済」となる。',
  237. '『碧空の加護(オルガ)』 自身のオーナーズネイルひとつの「使用済」を解除する。',
  238. '『思考妨害(あ、あれ見て?)』 ダイスロールに使用されたダイスの内、最大ふたつまでを指定する。それらのダイスを振り直させる。',
  239. '『碩学式回路(ジーニアス・サーキット)』 【ドロゥ:3】を行い、セットダイスから任意のふたつを取り除く。',
  240. '『碩学式"大"回路(ジーニアス・メガ・サーキット)』 任意のプレイヤー1人を対象とする。対象のオーナーズネイルを見る。その中から1枚を指定する。そのオーナーズネイルに以下の一文を追加する。「この効果を解決した後、自身に【アタック:5】を行う。」',
  241. '『偉大なる集合知(ハイアラキ)』 【ドロゥ:6】を行い、セットダイスから任意のみっつを取り除く。',
  242. '『碧空を越える者(ストラトスフィア・ブレイヴ)』 【ドロゥ:自身のリヴラドールの現在の高度】を行う。',
  243. '『深淵なる熟慮(わるだくみ)』 【ドロゥ:2】を行う。この時、6の出目を出したダイスはセットされず、取り除かれる。',
  244. '『深遠たる秩序(知識こそが正義)』 1~6の内、数字をひとつ指定する。このドロゥフェイズの間、全てのプレイヤーが行う【ドロゥ:X】では、指定した出目を出したダイスはセットすることが出来ない。',
  245. '『深淵より至れ、始まりへ(アマランサス・レプリカ)』 自身の「シールドレス」を1枚破壊する。【ドロゥ:3】を行い、自身のオーナーズネイルひとつの「使用済」を解除する。',
  246. '『深遠より至れ原初の森(混沌の森)』 リヴラドール1体を対象とする。対象の現在のパッシヴドレスと、自身のパッシヴドレスを交換する。この効果はクリンナップフェイズまで継続する。(効果中にパッシヴドレスが破壊されていた場合、破壊される前のパッシヴドレスに戻る)',
  247. ],
  248. 'GL' => [
  249. '『隕鉄の剣(メテオ・ブランド)』 対象に【アタック:緑Asレベル+2《OD》】を行う。',
  250. '『大樹の槌(トネリコ・ハンマー)』 対象に【アタック:緑Asレベル+1】を行い、続けて【エクストルード】を行う。',
  251. '『巨腕の操者(ストレングス・アーム)』 対象に【アタック:5】を行い、【アタック:2】を行い、続けて【エクストルード】を行う。',
  252. '『地を割る弾丸(ガイア・バレット)』 対象に【アタック:3《OD》】を行う。',
  253. '『踏み割り進め!(デストラクトウォーク)』 【ムーヴ:1】を行う。移動先のセルの「高度」を1減少する(高度は0より低い値にはならない)。',
  254. '『鋼の木樹を纏うように(ワイヤーアクション)』 【ムーヴ:1】を行う。自身が「高度:5」より高いセルから移動する場合、代わりに任意の座標へ移動する。',
  255. '『より大きく!(ビッグ・アンド・ビガー)』 直後に行うアタックネイルでは、合計3以上の成功数が出た場合、攻撃対象の「シールドレス」を追加でもう1枚破壊する。',
  256. '『より強靭に!(アンド・タフ)』 直後に行うアタックネイルで、合計3以上の成功数が出た場合、自身の「シールドレス」を1枚回復する。',
  257. '『翼の切断(まっさかさまにおちなさい)』 対象の「高度」を0に変更する。移動先のセルに「高度」が設定されている場合はその「高度」に変更する。',
  258. '『茸の道(マッシュロード)』 即座に【ムーヴ:1】を行う。',
  259. '『分かれ道(ロード・トゥワイス)』 対象の移動距離を1減少する。',
  260. ],
  261. 'GD' => [
  262. '『仮面舞踏会(マスカレイド)』',
  263. '『黙示の鎧(アポカリプス)』 自身が「高度:0」に存在する間、自身のブロックナンバーに「5、6」を追加する。',
  264. '『昇華の階段(スパイラル・アセンション)』 スタンバイフェイズ毎に、ダイスを2個振り、セルをひとつ指定して良い。そうした場合、そのセルの高度はダイスので目の合計値に変更される。',
  265. '『忘却の森(フォレスト:ジ オブリビオン)』 自身が行う【アタック:X】で2以上の成功数を出していた場合、破壊する「シールドレス」の枚数は1枚ではなく、成功数の値に等しくなる。',
  266. '『永遠に続く一日(バンデッド アゲート:ザ ドリーミング)』 自身の全てのネイルの《OD》指定された値を「5」増加する(この計算は、他の《OD》指定された数値を変動させる効果の前に行われる)',
  267. ],
  268. 'GO' => [
  269. '『限定巨大化(リミテッド・グロウス)』 このラウンドの終了時まで、自身のリヴラネイルの【アタック:X】は【アタック:X+1】に変更される。',
  270. '『被覆の盾(シュラウド・シールド)』 このアタックネイルの成功数を1減少する。',
  271. '『自然の叡智(ネイチャーズ・ウィズダム)』 アタックネイル、リアクトネイルのいずれか一方を指定する。全てのプレイヤーはこのラウンド終了時まで、選択されたネイルを使用することが出来ない。',
  272. '『茨の道(ソーン・ロード)』 直後のムーヴネイルで移動を行ったユニットを対象とし、【アタック:2】を行う。',
  273. '『小さな花園(リトル・リトル・フラワーガーデン)』 このアタックネイルの【アタック:X】を【アタック:X-1】に変更する。',
  274. '『バジリスクの寄せ餌(バジリスク・ルア)』 このラウンドの終了時まで、全てのユニットはアタックネイルを使用する度に、使用したユニット自身に【アタック:1】を行う。',
  275. '『生命の芽吹き(カム・イントゥ・バッズ)』 セットダイスを2個取り除く。自身のシールドレスを1枚回復する。',
  276. '『絡めとり(まちなさい!)』 ユニット1体を対象とする。対象が「高度:1」以上の高度に存在する場合、対象の行う全てのダイスロールの出目を1減少する。',
  277. '『繁栄の礎(プロスペリティ)』 直後の自身のドロゥフェイズで、ドロゥを行わないことを選ぶ代わりに、自身の緑のAsレベルを1上昇しても良い。',
  278. '『なる(ように)なる(ケ・セラ・セラ)』 自身のオーナーズネイルの「使用済」を解除する。',
  279. '『現代の災厄の象徴(すけいるどわーむ)』 ユニット1体を対象とする。対象はこのラウンドの終了時までアタックネイルを除くリヴラネイルを使用することが出来ない。また、対象が行うアタックネイルの【アタック:X】は、【アタック:X+2】に変更される。',
  280. '『吠え猛る龍禍(ワン・ゼイ・フィア)』 全てのユニットは、そのユニット自身に対して【アタック:そのユニットが存在する高度】を行う。この攻撃によって1枚以上シールドレスが破壊されたユニットは、自身のセットダイスを2個取り除く。',
  281. '『緩やかなる原初の監獄(エンクロージア)』 貴女を含む全てのプレイヤーは、そのプレイヤー自身のシールドレスを1枚回復することを選んでも良い。その後、貴女はこれによって回復したシールドレスの合計枚数に等しい数のシールドレスをさらに回復する。',
  282. '『裏切りの大渦(ベトレイアル・メイルストロム)』 ユニット1体を対象とする。対象に【アタック:3】を行い、【アタック:2】を行う。その後対象は【ドロゥ:1】を行う。',
  283. '『秩序の大渦(メイルストロム・オーダー)』 このラウンドの終了時まで、全てのユニットはアタックネイルを使用することが出来ない。',
  284. '『憤怒の大渦(アンガー・メイルストロム)』 全てのプレイヤーのシールドレスを、現在最もシールドレスの枚数が少ないプレイヤーの枚数と同じ枚数に変更する。',
  285. '『神秘の大渦(ミスティック・メイルストロム)』 使用されたオーナーズネイルの効果は発揮されず、「使用済」となる。',
  286. ],
  287. 'ED' => [
  288. '『黒の餓狼(ブラックソード・ウルフ)』 1.このユニットが使用するアタックネイルの対象を1増加しても良い。 2.このユニットの【アタック:X】で3以上の成功数が出た場合、自身のシールドレスを1枚回復する。',
  289. '『白の鋼鉄騎士(ぼくめつのりゅう)』 このユニットが使用するアタックネイルの対象を1増加しても良い。',
  290. '『赤の飛龍(クロムクラーク)』 1.このユニットが使用するアタックネイルの対象を1増加しても良い。 2.このユニットのアタックネイルの【アタック:X】のXを2増加する。',
  291. '『青の翼龍(ヴァイエル)』 1.このユニットが使用するアタックネイルの対象を1増加しても良い。 2.このユニットが「高度:9」以上に存在する限り、ブロックナンバーに4を追加する。',
  292. '『緑の操り人形(グリーン・ジェイラー)』 自身を含む、このユニットと同じセルに存在するユニットは、クリンナッププロセスの終了時にシールドレスを1枚失う。',
  293. ],
  294. }.freeze
  295. 1 register_prefix(DECKS.keys)
  296. end
  297. end
  298. end

lib/bcdice/game_system/LogHorizon.rb

98.72% lines covered

92.73% branches covered

235 relevant lines. 232 lines covered and 3 lines missed.
110 total branches, 102 branches covered and 8 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/base"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class LogHorizon < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'LogHorizon'
  8. # ゲームシステム名
  9. 1 NAME = 'ログ・ホライズンTRPG'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'ろくほらいすんTRPG'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~MESSAGETEXT
  14. ■ 判定 (xLH±y>=z)
  15.  xD6の判定。クリティカル、ファンブルの自動判定を行います。
  16.  x:xに振るダイス数を入力。
  17.  ±y:yに修正値を入力。±の計算に対応。省略可能。
  18.  >=z:zに目標値を入力。±の計算に対応。省略可能。
  19.  例) 3LH 2LH>=8 3LH+1>=10
  20. ■ 消耗表 (tCTx±y$z)
  21.  PCT 体力/ECT 気力/GCT 物品/CCT 金銭
  22.  x:CRを指定。
  23.  ±y:修正値。+と-の計算に対応。省略可能。
  24.  $z:$を付けるとダイス目を z 固定。表の特定の値参照用に。省略可能。
  25.  例) PCT1 ECT2+1 GCT3-1 CCT3$5
  26. ■ 消耗表ロール (CTx±y)
  27.  消耗表ロールを行い、出目を決定する。
  28.  x:CRを指定。指定できますが、無視されます。省略可能
  29.  ±y:修正値。+と-の計算に対応。省略可能。
  30. ■ 財宝表 (tTRSx±y$)
  31.  LHZB1記載の財宝表
  32.  CTRS 金銭/MTRS 魔法素材/ITRS 換金アイテム/※HTRS ヒロイン/GTRS ゴブリン財宝表
  33.  x:CRを指定。省略時はダイス値 0 固定で修正値の表参照。《ゴールドフィンガー》使用時など。
  34.  ±y:修正値。+と-の計算に対応。省略可能。
  35.  $:$を付けると財宝表のダイス目を7固定(1回分のプライズ用)。省略可能。
  36.  例) CTRS1 MTRS2+1 ITRS3-1 ITRS+27 CTRS3$
  37. ■ 財宝表(拡張ルールブック) (tTRSEx±y$)
  38.  LHZB2記載の財宝表
  39.  CTRSE 金銭/MTRSE 魔法素材/ITRSE 換金アイテム/OTRSE そのほか
  40.  記法は財宝表と同様
  41. ■ 財宝表ロール (TRSx±y)
  42.  財宝表ロールを行い、出目を決定する。
  43.  x:CRを指定。省略時はCR 0として扱う
  44.  ±y:修正値。+と-の計算に対応。省略可能。
  45. ■ イースタル探索表 (ESTLx±y$z)
  46.  x:CRを指定。省略時はダイス値 0 固定で修正値の表参照。
  47.  ±y:修正値。+と-の計算に対応。省略可能。
  48.  $z:$を付けるとダイス目を z 固定。特定CRの表参照用に。省略可能。
  49.  例) ESTL1 ESTL+15 ESTL2+1$5 ESTL2-1$5
  50. ■ プレフィックスドマジックアイテム効果表 (MGRx)
  51.  xはMGを指定。(LHZB1用)
  52. ■ 楽器種別表† (MIIx)
  53.  xは楽器の種類(1~6を指定)、省略可能
  54.  1 打楽器1/2 鍵盤楽器/3 弦楽器1/4 弦楽器2/5 管楽器1/6 管楽器2
  55. ■ 特殊消耗表☆ (tSCTx±y$z)
  56.  消耗表と同様、ただしCRは省略可能。
  57.  ESCT ロデ研は爆発だ!/CSCT アルヴの呪いじゃ!
  58. ■ ロデ研の新発明ランダム決定表※ (IATt)
  59.  IATA 特徴A(メリット)/IATB 特徴B(デメリット)/IATL 見た目/IATT 種類
  60.  tを省略すると全て表示。tにA/B/L/Tを任意の順で連結可能
  61.  例)IAT IATALT IATABBLT IATABL
  62. ■ 表
  63.  ・パーソナリティタグ表 (PTAG)
  64.  ・交友表 (KOYU)
  65.  ・攻撃命中箇所ランダム決定表※ (HLOC)
  66.  ・PC名ランダム決定表※ (PCNM)
  67.  ・アキバの街で遭遇するトラブルランダム決定表※ (TIAS)
  68.  ・廃棄児ランダム決定表※ (ABDC)
  69. †印は☆印は「イントゥ・ザ・セルデシア さらなるビルドの羽ばたき(1)」より、
  70. ☆印はセルデシア・ガゼット「できるかな66」Vol.1より、
  71. ※印は「実録・七面体工房スタッフ座談会(夏の陣)」より。利用法などはそちら参照。
  72. ・D66ダイスあり
  73. MESSAGETEXT
  74. 1 register_prefix('\d+LH', '\w+CT', 'CT', '\w+TRS', 'TRS', 'IAT', 'TIAS', 'ABDC', 'MII', 'ESTL')
  75. 1 def initialize(command)
  76. 411 super(command)
  77. 411 @d66_sort_type = D66SortType::NO_SORT
  78. end
  79. 1 def eval_game_system_specific_command(command)
  80. 411 getCheckRollDiceCommandResult(command) ||
  81. roll_consumption(command) ||
  82. roll_consumption_table(command) ||
  83. roll_treasure(command) ||
  84. roll_treasure_table(command) ||
  85. roll_treasure_table_b2(command) ||
  86. getInventionAttributeTextDiceCommandResult(command) ||
  87. getTroubleInAkibaStreetDiceCommandResult(command) ||
  88. getAbandonedChildDiceCommandResult(command) ||
  89. getMusicalInstrumentTypeDiceCommandResult(command) ||
  90. roll_eastal_exploration_table(command) ||
  91. roll_tables(command, self.class::TABLES)
  92. end
  93. 1 private
  94. 1 def getCheckRollDiceCommandResult(command)
  95. 411 parser = Command::Parser.new(/\d+LH/, round_type: round_type)
  96. .restrict_cmp_op_to(nil, :>=)
  97. 411 parsed = parser.parse(command)
  98. 411 else: 10 then: 401 unless parsed
  99. 401 return nil
  100. end
  101. 10 dice_count = parsed.command.to_i
  102. 10 dice_list = @randomizer.roll_barabara(dice_count, 6)
  103. 10 dice_total = dice_list.sum()
  104. 10 total = dice_total + parsed.modify_number
  105. 10 result = result_text(dice_count, dice_list, total, parsed)
  106. sequence = [
  107. 10 "(#{parsed})",
  108. "#{dice_total}[#{dice_list.join(',')}]#{Format.modifier(parsed.modify_number)}",
  109. total,
  110. result.text,
  111. ].compact
  112. 10 result.text = sequence.join(" > ")
  113. 10 result
  114. end
  115. 1 def result_text(dice_count, dice_list, total, parsed)
  116. 10 then: 2 if dice_list.count(6) >= 2
  117. 2 else: 8 Result.critical(translate("LogHorizon.LH.critical"))
  118. 8 then: 2 elsif dice_list.count(1) >= dice_count
  119. 2 else: 6 Result.fumble(translate("LogHorizon.LH.fumble"))
  120. 6 then: 2 elsif parsed.cmp_op.nil?
  121. 2 else: 4 Result.new
  122. 4 then: 2 elsif total >= parsed.target_number
  123. 2 Result.success(translate("success"))
  124. else: 2 else
  125. 2 Result.failure(translate("failure"))
  126. end
  127. end
  128. 1 def getValue(text, defaultValue)
  129. then: 0 else: 0 return defaultValue if text.nil? || text.empty?
  130. ArithmeticEvaluator.eval(text)
  131. end
  132. # 消耗表ロール
  133. 1 def roll_consumption(command)
  134. 401 m = /^CT\d*([+\-\d]+)?$/.match(command)
  135. 401 else: 4 then: 397 return nil unless m
  136. 4 modifier = ArithmeticEvaluator.eval(m[1])
  137. 4 formated_modifier = Format.modifier(modifier)
  138. 4 dice = @randomizer.roll_once(6)
  139. 4 else: 2 then: 2 interim_expr = dice.to_s + formated_modifier unless formated_modifier.empty?
  140. sequence = [
  141. 4 "(1D6#{formated_modifier})",
  142. interim_expr,
  143. dice + modifier,
  144. ].compact
  145. 4 return sequence.join(" > ")
  146. end
  147. ### 消耗表 ###
  148. 1 def roll_consumption_table(command)
  149. 397 m = /(P|E|G|C|ES|CS)CT(\d+)?([+\-\d]+)?(?:\$(\d+))?/.match(command)
  150. 397 else: 166 then: 231 return nil unless m
  151. 166 table = construct_consumption_table(m[1])
  152. 166 cr = m[2].to_i
  153. 166 modifier = ArithmeticEvaluator.eval(m[3])
  154. 166 then: 35 else: 131 table.fix_dice_value(m[4].to_i) if m[4]
  155. 166 return table.roll(cr, modifier, @randomizer)
  156. end
  157. 1 def construct_consumption_table(type)
  158. table =
  159. 166 else: 0 case type
  160. when: 37 when "P"
  161. 37 translate("LogHorizon.CT.PCT")
  162. when: 24 when "E"
  163. 24 translate("LogHorizon.CT.ECT")
  164. when: 24 when "G"
  165. 24 translate("LogHorizon.CT.GCT")
  166. when: 25 when "C"
  167. 25 translate("LogHorizon.CT.CCT")
  168. when: 28 when "ES"
  169. 28 translate("LogHorizon.CT.ESCT")
  170. when: 28 when "CS"
  171. 28 translate("LogHorizon.CT.CSCT")
  172. end
  173. 166 ConsumptionTable.new(table[:name], table[:items])
  174. end
  175. # 消耗表
  176. 1 class ConsumptionTable
  177. # @param name [String]
  178. # @param tables [Array[Hash{Integer => String}]]
  179. 1 def initialize(name, tables)
  180. 166 @name = name
  181. 166 @tables = tables
  182. 166 @dice_value = nil
  183. end
  184. # ダイスの値を固定する
  185. # @param dice [Integer]
  186. # @return [void]
  187. 1 def fix_dice_value(dice)
  188. 35 @dice_value = dice
  189. end
  190. 1 def roll(cr, modifier, randomizer)
  191. 166 table_index = ((cr - 1) / 5).clamp(0, @tables.size - 1)
  192. 166 items = @tables[table_index]
  193. 166 @dice_value ||= randomizer.roll_once(6)
  194. 166 total = @dice_value + modifier
  195. 166 chosen = items[total.clamp(0, 7)]
  196. 166 "#{@name}(#{total}[#{@dice_value}]) > #{chosen}"
  197. end
  198. end
  199. # 財宝表ロール
  200. 1 def roll_treasure(command)
  201. 231 m = /^TRS(\d+)?([+\-\d]+)?$/.match(command)
  202. 231 else: 4 then: 227 return nil unless m
  203. 4 character_rank = m[1].to_i
  204. 4 modifier = ArithmeticEvaluator.eval(m[2])
  205. 4 dice_list = @randomizer.roll_barabara(2, 6)
  206. 4 dice_total = dice_list.sum
  207. 4 total = dice_total + character_rank * 5 + modifier
  208. 4 return "(2D6+#{character_rank}*5#{Format.modifier(modifier)}) > "\
  209. "#{dice_total}[#{dice_list.join(',')}]#{Format.modifier(character_rank * 5 + modifier)} > "\
  210. "#{total}"
  211. end
  212. ### 財宝表 ###
  213. 1 def roll_treasure_table(command)
  214. 227 m = /^([CMIHG]TRS)(\d+)?([+\-\d]+)?(\$)?$/.match(command)
  215. 227 else: 73 then: 154 return nil unless m
  216. 73 type = m[1]
  217. 73 table = construct_treasure_table(type)
  218. 73 character_rank = m[2].to_i
  219. 73 modifier = ArithmeticEvaluator.eval(m[3])
  220. 73 then: 5 else: 68 return translate("LogHorizon.TRS.need_cr", command: command) if character_rank == 0 && modifier == 0
  221. 68 then: 11 else: 57 table.fix_dice_value(7) if m[4]
  222. 68 return table.roll(character_rank, modifier, @randomizer)
  223. end
  224. 1 def construct_treasure_table(type)
  225. 73 then: 22 if type == "HTRS"
  226. 22 HeroineTreasureTable.from_i18n("LogHorizon.TRS.HTRS", @locale)
  227. else: 51 else
  228. 51 TreasureTable.from_i18n("LogHorizon.TRS.#{type}", @locale)
  229. end
  230. end
  231. # 拡張ルール財宝表
  232. 1 def roll_treasure_table_b2(command)
  233. 154 m = /^([CMIO]TRSE)(\d+)?([+\-\d]+)?(\$)?$/.match(command)
  234. 154 else: 38 then: 116 return nil unless m
  235. 38 type = m[1]
  236. 38 table = ExpansionTreasureTable.from_i18n("LogHorizon.TRSE.#{type}", @locale)
  237. 38 character_rank = m[2].to_i
  238. 38 modifier = ArithmeticEvaluator.eval(m[3])
  239. 38 then: 2 else: 36 return translate("LogHorizon.TRS.need_cr", command: command) if character_rank == 0 && modifier == 0
  240. 36 then: 2 else: 34 table.fix_dice_value(7) if m[4]
  241. 36 return table.roll(character_rank, modifier, @randomizer)
  242. end
  243. # 財宝表
  244. 1 class TreasureTable
  245. 1 include Translate
  246. 1 class << self
  247. 1 def from_i18n(key, locale)
  248. 111 table = I18n.translate(key, raise: true, locale: locale)
  249. 111 new(table[:name], table[:items], locale)
  250. end
  251. end
  252. # @param name [String]
  253. # @param items [Hash{Integer => String}]
  254. 1 def initialize(name, items, locale)
  255. 111 @name = name
  256. 111 @items = items
  257. 111 @locale = locale
  258. 111 @dice_list = nil
  259. end
  260. # プライズ取得用にダイスの値を固定する
  261. # @param dice [Integer]
  262. # @return [void]
  263. 1 def fix_dice_value(dice)
  264. 13 @dice_list = [dice]
  265. end
  266. # @param cr [Integer]
  267. # @param modifier [Integer]
  268. # @param randomizer [Randomizer]
  269. # @return [String, nil]
  270. 1 def roll(cr, modifier, randomizer)
  271. 104 then: 0 else: 104 return nil if cr == 0 && modifier == 0
  272. index =
  273. 104 then: 12 if cr == 0 && modifier != 0
  274. 12 modifier # modifierの値のみ設定されている場合には、その値の項目をダイスロールせずに参照する
  275. else: 92 else
  276. 92 @dice_list ||= randomizer.roll_barabara(2, 6)
  277. 92 @dice_list.sum() + 5 * cr + modifier
  278. end
  279. 104 chosen = pick_item(index)
  280. 104 then: 92 else: 12 then: 92 else: 0 dice_str = "[#{@dice_list&.join(',')}]" if @dice_list
  281. 104 "#{@name}(#{index}#{dice_str}) > #{chosen}"
  282. end
  283. 1 private
  284. # @param index [Integer]
  285. # @return [String]
  286. 1 def pick_item(index)
  287. 48 then: 2 if index <= 6
  288. 2 else: 46 translate("LogHorizon.TRS.below_lower_limit", value: 6) # 6以下の出目は未定義です
  289. 46 then: 31 elsif index <= 62
  290. 31 else: 15 @items[index]
  291. 15 then: 3 elsif index <= 72
  292. 3 else: 12 "#{@items[index - 10]}&80G"
  293. 12 then: 3 elsif index <= 82
  294. 3 else: 9 "#{@items[index - 20]}&160G"
  295. 9 then: 6 elsif index <= 87
  296. 6 "#{@items[index - 30]}&260G"
  297. else: 3 else
  298. 3 translate("LogHorizon.TRS.exceed_upper_limit", value: 88) # 88以上の出目は未定義です
  299. end
  300. end
  301. end
  302. # ヒロイン財宝表
  303. 1 class HeroineTreasureTable < TreasureTable
  304. # @param index [Integer]
  305. # @return [String]
  306. 1 def pick_item(index)
  307. 20 then: 0 if index <= 6
  308. else: 20 translate("LogHorizon.TRS.below_lower_limit", value: 6)
  309. 20 then: 16 elsif index <= 53
  310. 16 @items[index]
  311. else: 4 else
  312. 4 translate("LogHorizon.TRS.exceed_upper_limit", value: 54)
  313. end
  314. end
  315. end
  316. # 拡張ルール財宝表
  317. 1 class ExpansionTreasureTable < TreasureTable
  318. # @param index [Integer]
  319. # @return [String]
  320. 1 def pick_item(index)
  321. 36 then: 2 if index <= 6
  322. 2 else: 34 translate("LogHorizon.TRS.below_lower_limit", value: 6)
  323. 34 then: 20 elsif index <= 162
  324. 20 else: 14 @items[index]
  325. 14 then: 2 elsif index <= 172
  326. 2 else: 12 "#{@items[index - 10]}&200G"
  327. 12 then: 2 elsif index <= 182
  328. 2 else: 10 "#{@items[index - 20]}&400G"
  329. 10 then: 8 elsif index <= 187
  330. 8 "#{@items[index - 30]}&600G"
  331. else: 2 else
  332. 2 translate("LogHorizon.TRS.exceed_upper_limit", value: 188)
  333. end
  334. end
  335. end
  336. # ロデ研の新発明ランダム決定表
  337. 1 def getInventionAttributeTextDiceCommandResult(command)
  338. 116 else: 14 then: 102 return nil unless command =~ /IAT([ABMDLT]*)/
  339. 14 tableName = translate("LogHorizon.IAT.name")
  340. 14 then: 12 else: 2 table_indicate_string = Regexp.last_match(1) && Regexp.last_match(1) != '' ? Regexp.last_match(1) : 'MDLT'
  341. 14 is_single = (table_indicate_string.length == 1)
  342. 14 result = []
  343. 14 number = []
  344. 14 table_indicate_string.split(//).each do |char|
  345. 32 dice_result = @randomizer.roll_once(6)
  346. 32 number << dice_result.to_s
  347. 32 else: 0 table = case char
  348. when: 8 when 'A', 'M'
  349. 8 translate("LogHorizon.IAT.A")
  350. when: 8 when 'B', 'D'
  351. 8 translate("LogHorizon.IAT.B")
  352. when: 8 when 'L'
  353. 8 translate("LogHorizon.IAT.L")
  354. when: 8 when 'T'
  355. 8 translate("LogHorizon.IAT.T")
  356. end
  357. 32 chosen = table[:items][dice_result - 1]
  358. 32 then: 8 else: 24 if is_single
  359. 8 chosen = "#{table[:name]}:#{chosen}"
  360. end
  361. 32 result.push(chosen)
  362. end
  363. 14 return "#{tableName}([#{number.join(',')}]) > #{result.join(' ')}"
  364. end
  365. # アキバの街で遭遇するトラブルランダム決定表
  366. 1 def getTroubleInAkibaStreetDiceCommandResult(command)
  367. 102 else: 6 then: 96 return nil unless command == "TIAS"
  368. 6 roll_random_table("LogHorizon.TIAS")
  369. end
  370. # 廃棄児ランダム決定表
  371. 1 def getAbandonedChildDiceCommandResult(command)
  372. 96 else: 6 then: 90 return nil unless command == "ABDC"
  373. 6 roll_random_table("LogHorizon.ABDC")
  374. end
  375. 1 def roll_random_table(key)
  376. 12 table = translate(key)
  377. 12 tables = table[:tables]
  378. 12 dice_list = @randomizer.roll_barabara(tables.size, 6)
  379. 72 result = dice_list.map.with_index { |n, index| tables[index][n - 1] }
  380. 12 return "#{table[:name]}([#{dice_list.join(',')}]) > #{result.join(' ')}"
  381. end
  382. # 楽器種別表
  383. 1 def getMusicalInstrumentTypeDiceCommandResult(command)
  384. 90 else: 10 then: 80 return nil unless command =~ /MII(\d?)/
  385. 10 is_roll = !(Regexp.last_match(1) && Regexp.last_match(1) != '')
  386. 10 then: 6 else: 4 type = is_roll ? @randomizer.roll_once(6) : Regexp.last_match(1).to_i
  387. 10 then: 0 else: 10 return nil if type < 1 || 6 < type
  388. 10 tableName = translate("LogHorizon.MII.name")
  389. 10 type_name = translate("LogHorizon.MII.type_list")[type - 1]
  390. 10 dice = @randomizer.roll_once(6)
  391. 10 result = translate("LogHorizon.MII.items")[type - 1][dice - 1]
  392. 10 then: 6 else: 4 return tableName.to_s + (is_roll ? "(#{type})" : '') + " > #{type_name}(#{dice}) > #{result}"
  393. end
  394. # イースタル探索表
  395. 1 def roll_eastal_exploration_table(command)
  396. 80 m = /ESTL(\d+)?([+\-\d]+)?(?:\$(\d+))?/.match(command)
  397. 80 else: 44 then: 36 return nil unless m
  398. 44 then: 1 else: 43 return nil if m[1].nil? && m[2].nil? && m[3].nil?
  399. 43 character_rank = m[1].to_i
  400. 43 modifier = ArithmeticEvaluator.eval(m[2])
  401. 43 then: 27 else: 16 fixed_dice_value = m[3]&.to_i
  402. dice_list =
  403. 43 then: 27 if fixed_dice_value
  404. 27 else: 16 [fixed_dice_value]
  405. 16 then: 7 elsif character_rank == 0
  406. 7 []
  407. else: 9 else
  408. 9 @randomizer.roll_barabara(2, 6)
  409. end
  410. 43 else: 7 then: 36 dice_str = "[#{dice_list.join(',')}]" unless dice_list.empty?
  411. 43 total = (dice_list.sum() + character_rank * 5 + modifier).clamp(7, 162)
  412. 43 table_name = translate("LogHorizon.ESTL.name")
  413. 43 table = translate("LogHorizon.ESTL.items")
  414. 43 chosen = table[total].chomp
  415. 43 return "#{table_name}(#{total}#{dice_str})\n#{chosen}"
  416. end
  417. 1 class << self
  418. 1 private
  419. 1 def translate_tables(locale)
  420. {
  421. 2 "PTAG" => DiceTable::D66Table.from_i18n("LogHorizon.table.PTAG", locale),
  422. "KOYU" => DiceTable::D66Table.from_i18n("LogHorizon.table.KOYU", locale),
  423. "MGR1" => DiceTable::D66Table.from_i18n("LogHorizon.table.MGR1", locale),
  424. "MGR2" => DiceTable::D66Table.from_i18n("LogHorizon.table.MGR2", locale),
  425. "MGR3" => DiceTable::D66Table.from_i18n("LogHorizon.table.MGR3", locale),
  426. "HLOC" => DiceTable::D66Table.from_i18n("LogHorizon.table.HLOC", locale),
  427. "PCNM" => DiceTable::D66Table.from_i18n("LogHorizon.table.PCNM", locale),
  428. }
  429. end
  430. end
  431. 1 TABLES = translate_tables(:ja_jp)
  432. 1 register_prefix(TABLES.keys)
  433. end
  434. end
  435. end

lib/bcdice/game_system/LogHorizon_Korean.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/LogHorizon"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class LogHorizon_Korean < LogHorizon
  6. # ゲームシステムの識別子
  7. 1 ID = 'LogHorizon:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '로그 호라이즌'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:로그 호라이즌'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~MESSAGETEXT
  14. ■ 판정(xLH±y>=z)
  15.  xD6의 판정.크리티컬, 펌블의 자동 판정을 실시합니다.
  16.  x:x로 굴릴 주사위의 수를 입력합니다.
  17.  ±y:y로 수정치를 입력합니다. ±의 계산에 대응하며 생략이 가능합니다.
  18. >=z:z로 목표값을 입력합니다. ±의 계산에 대응하며 생략이 가능합니다.
  19.  예시) 3LH 2LH>=8 3LH+1>=10
  20. ■ 소모표(tCTx±y$z)
  21.  PCT 체력/ECT 기력/GCT 물품/CCT 금전
  22.  x:CR을 지정합니다.
  23.  ±y:수정치, +와 -의 계산에 대응하며 생략이 가능합니다.
  24.  $z:$를 붙이면 주사위 눈을 z고정합니다. 표의 특정 값 참조용으로 사용하며.생략 가능.
  25.  例) PCT1 ECT2+1 GCT3-1 CCT3$5
  26. ■ 消耗表ロール (CTx±y)
  27.  消耗表ロールを行い、出目を決定する。
  28.  x:CRを指定。指定できますが、無視されます。省略可能
  29.  ±y:修正値。+と-の計算に対応。省略可能。
  30. ■ 재물표(tTRSx±y$)
  31.  CTRS 금전/MTRS 마법소재/ITRS 환전 아이템/※HTRS 히로인/GTRS 고블린 재보표
  32.  x:CR을 지정합니다. 생략시에는 다이치 0고정으로 수정치의 표를 참조.《골드 핑거》사용 시 등.
  33.  ±y:수정치, +와 -의 계산에 대응하며 생략이 가능합니다.
  34.  $:$을 붙이면 재물표의 다이스를 7로 고정합니다.(1차 분량의 프라이즈 용도)생략이 가능합니다.
  35.  예시) CTRS1 MTRS2+1 ITRS3-1 ITRS+27 CTRS3$
  36. ■ 財宝表(拡張ルールブック) (tTRSEx±y$)
  37.  LHZB2記載の財宝表
  38.  CTRSE 金銭/MTRSE 魔法素材/ITRSE 換金アイテム/OTRSE そのほか
  39.  記法は財宝表と同様
  40. ■ 財宝表ロール (TRSx±y)
  41.  財宝表ロールを行い、出目を決定する。
  42.  x:CRを指定。省略時はCR 0として扱う
  43.  ±y:修正値。+と-の計算に対応。省略可能。
  44. ■ 이스탈 탐색표 (ESTLx±y$z)
  45.  x:CRを指定。省略時はダイス値 0 固定で修正値の表参照。
  46.  ±y:修正値。+と-の計算に対応。省略可能。
  47.  $z:$を付けるとダイス目を z 固定。特定CRの表参照用に。省略可能。
  48.  例) ESTL1 ESTL+15 ESTL2+1$5 ESTL2-1$5
  49. ■ 프리픽스드 매직아이템 효과 표(MGRx)
  50.  x는 MG를 지정합니다.
  51. ■ 악기 종류 표† (MIIx)
  52.  x는 악기의 종류를 지정합니다.(1~6를 지정) 생략이 가능합니다.
  53.  1 타악기1/2 건반악기/3 현악기1/4 현악기2/5 관악기1/6 관악기2
  54. ■ 특수 소모표☆ (tSCTx±y$z)
  55.  소모표와 마찬가지로 지정합니다. 다만 CR은 생략이 가능합니다.
  56.  ESCT 로데릭 연구소는 폭발했다!/CSCT 알브의 저주다!
  57. ■ 로데릭 연구소의 새로운 발명 랜덤 결정표※ (IATt)
  58.  IATA 특징A(장점)/IATB 특징B(단점)/IATL 외형/IATT 종류
  59.  t를 생략할 경우 모두 표시합니다. t에 A/B/L/T를 임의의 순서로 연결 할 수 있습니다.
  60.  例)IAT IATALT IATABBLT IATABL
  61. ■ 표
  62.  ・퍼스널리티 태그 표 (PTAG)
  63.  ・교우표 (KOYU)
  64.  ・공격 명중 장소 랜덤 결정표※ (HLOC)
  65.  ・PC명 랜덤 결정표※ (PCNM)
  66.  ・아키바 거리에서 발생하는 문제 랜덤결정 표※ (TIAS)
  67.  ・버려진 아이 랜덤 결정 표※ (ABDC)
  68. †표시와 ☆표시는「인투・더・셀덴시아 새로운 빌드의 날개짓(1)」에서、
  69. ☆표시는 셀덴시아・가제트「D 되기는 할까? 66」Vol.1에서、
  70. ※표시는「실록・칠면체공방 좌담회(여름의 장)」에서 참조했습니다. 이용법은 항목을 참조해주세요.
  71. ・D66다이스도 있습니다.
  72. ・역자의 말 : 「실록・칠면체공방 좌담회(여름의 장)」은 한국에서 발매하지 않습니다. 참고해주세요.
  73. ・이니티움님, 광황님, CoC방 여러분 감사합니다. by호흡도의식하면귀찮아
  74. MESSAGETEXT
  75. 1 register_prefix_from_super_class()
  76. 1 def initialize(command)
  77. 143 super(command)
  78. 143 @locale = :ko_kr
  79. end
  80. 1 TABLES = translate_tables(:ko_kr)
  81. end
  82. end
  83. end

lib/bcdice/game_system/LostRecord.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class LostRecord < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'LostRecord'
  7. # ゲームシステム名
  8. 1 NAME = 'ロストレコード'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ろすとれこおと'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ※このダイスボットは部屋のシステム名表示用となります。
  14. D66を振った時、小さい目が十の位になります。
  15. MESSAGETEXT
  16. 1 def initialize(command)
  17. 2 super(command)
  18. # D66は昇順に
  19. 2 @d66_sort_type = D66SortType::ASC
  20. end
  21. end
  22. end
  23. end

lib/bcdice/game_system/LostRoyal.rb

99.03% lines covered

96.88% branches covered

103 relevant lines. 102 lines covered and 1 lines missed.
32 total branches, 31 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class LostRoyal < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'LostRoyal'
  7. # ゲームシステム名
  8. 1 NAME = 'ロストロイヤル'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ろすとろいやる'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・D66ダイスあり
  14. 行為判定
  15.  LR[x,x,x,x,x,x]
  16.   x の並びには【判定表】の数値を順番に入力する。
  17.   (例: LR[1,3,0,1,2,3] )
  18. ファンブル表
  19.  FC
  20. 風力決定表
  21.  WPC
  22. 感情決定表
  23.  EC
  24. 希望点の決定
  25.  HRx
  26.   x にはダイスの数( 1 - 2 )を指定
  27. INFO_MESSAGE_TEXT
  28. 1 register_prefix('LR\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\]', 'FC', 'WPC', 'EC', 'HR[1-2]')
  29. 1 def initialize(command)
  30. 51 super(command)
  31. 51 @sort_add_dice = true
  32. 51 @d66_sort_type = D66SortType::NO_SORT
  33. end
  34. 1 def eval_game_system_specific_command(command)
  35. 50 else: 0 case command
  36. when: 14 when /LR\[([0-5]),([0-5]),([0-5]),([0-5]),([0-5]),([0-5])\]/i
  37. 14 return check_lostroyal([Regexp.last_match(1).to_i, Regexp.last_match(2).to_i, Regexp.last_match(3).to_i, Regexp.last_match(4).to_i, Regexp.last_match(5).to_i, Regexp.last_match(6).to_i,])
  38. when: 6 when /FC/
  39. 6 return roll_fumble_chart
  40. when: 13 when /WPC/
  41. 13 return roll_wind_power_chart
  42. when: 6 when /EC/
  43. 6 return roll_emotion_chart
  44. when: 11 when /HR([1-2])/
  45. 11 return roll_hope(Regexp.last_match(1).to_i)
  46. end
  47. return nil
  48. end
  49. 1 def check_lostroyal(checking_table)
  50. 14 keys = []
  51. 14 3.times do |_i|
  52. 42 key = @randomizer.roll_once(6)
  53. 42 keys << key
  54. end
  55. 56 scores = (keys.map { |k| checking_table[k - 1] }).to_a
  56. 14 total_score = scores.inject(:+)
  57. 14 chained_sequence = find_sequence(keys)
  58. 14 text = "3D6 => [#{keys.join(',')}] => (#{scores.join('+')}) => #{total_score}"
  59. 14 else: 2 then: 12 unless chained_sequence.nil? || chained_sequence.empty?
  60. 12 then: 3 else: 9 bonus = fumble_?(keys, chained_sequence) ? 3 : chained_sequence.size
  61. 12 text += " | #{chained_sequence.size} chain! (#{chained_sequence.join(',')}) => #{total_score + bonus}"
  62. 12 then: 5 else: 7 if chained_sequence.size >= 3
  63. 5 text += " [スペシャル]"
  64. end
  65. 12 then: 3 else: 9 if fumble_?(keys, chained_sequence)
  66. 3 text += " [ファンブル]"
  67. end
  68. end
  69. 14 return text
  70. end
  71. 1 def find_sequence(keys)
  72. 14 keys = keys.sort
  73. 14 sequences = (1...6).map do |start_key|
  74. 70 find_sequence_from_start_key(keys, start_key)
  75. end
  76. 87 sequences.select { |x| x.size > 1 }.max { |a, b| a.size <=> b.size }
  77. end
  78. 1 def find_sequence_from_start_key(keys, start_key)
  79. 70 chained_keys = []
  80. 70 key = start_key
  81. 70 body: 43 while keys.include? key
  82. 43 chained_keys << key
  83. 43 key += 1
  84. end
  85. 70 then: 11 else: 59 if !chained_keys.empty? && chained_keys[0] == 1
  86. 11 key = 6
  87. 11 body: 7 while keys.include? key
  88. 7 chained_keys.unshift key
  89. 7 key -= 1
  90. end
  91. end
  92. 70 return chained_keys
  93. end
  94. 1 def fumble_?(keys, chained_sequence)
  95. 24 chained_sequence.each do |k|
  96. 56 then: 6 else: 50 if keys.count(k) >= 2
  97. 6 return true
  98. end
  99. end
  100. 18 false
  101. end
  102. 1 def roll_fumble_chart
  103. 6 key = @randomizer.roll_once(6)
  104. 6 text = [
  105. "何かの問題で言い争い、主君に無礼を働いてしまう。あなたは主君の名誉点を1点失うか、【時間】を1点消費して和解の話し合いを持つか選べる。",
  106. "見過ごせば人々を不幸にする危険に遭遇する。あなたは逃げ出して冒険の名誉点を1点失うか、これに立ち向かい【命数】を2点減らすかを選べる。",
  107. "あなたが惹かれたのは好意に付け込む人だった。あなたはその場を去って恋慕の名誉点を1点失うか【正義】を1点減らして礼を尽くすかを選べる。",
  108. "金銭的な問題で、生命と魂の苦しみを背負う人に出会う。あなたは庇護の名誉点を1点失うか出費を3点増やすかを選べる。",
  109. "襲撃を受ける。苦もなく叩き伏せると、卑屈な態度で命乞いをしてきた。容赦なく命を奪い寛容の名誉点を1点失うか、密告によって【血路】が1D6点増えるかを選ぶことができる。",
  110. "風聞により、友が悪に身を貶めたと知る。共に並んだ戦場が色褪せる想いだ。戦友の名誉点を1点減らすか、【酒と歌】すべてを失うかを選べる。",
  111. ][key - 1]
  112. 6 return "1D6 => [#{key}] #{text}"
  113. end
  114. 1 def roll_wind_power_chart
  115. 13 key = 0
  116. 13 total_bonus = 0
  117. 13 text = ""
  118. 13 loop do
  119. 24 dice = @randomizer.roll_once(6)
  120. 24 key += dice
  121. add, bonus, current_text, = [
  122. 24 [true, 0, "ほぼ凪(振り足し)"],
  123. [true, 0, "弱い風(振り足し)"],
  124. [false, 0, "ゆるやかな風"],
  125. [false, 0, "ゆるやかな風"],
  126. [false, 1, "やや強い風(儀式点プラス1)"],
  127. [false, 2, "強い風(龍を幻視、儀式点プラス2)"],
  128. [false, 3, "体が揺らぐほどの風(龍を幻視、儀式点プラス3)"],
  129. ][[key, 7].min - 1]
  130. 24 total_bonus += bonus
  131. 24 then: 11 if key != dice
  132. 11 current_text = "1D6[#{dice}]+#{key - dice} #{current_text}"
  133. else: 13 else
  134. 13 current_text = "1D6[#{dice}] #{current_text}"
  135. end
  136. 24 then: 13 if text.empty?
  137. 13 text = current_text
  138. else: 11 else
  139. 11 text = "#{text} => #{current_text}"
  140. end
  141. 24 else: 11 then: 13 unless add
  142. 13 text += " [合計:儀式点 +#{total_bonus} ]"
  143. 13 return text
  144. end
  145. end
  146. end
  147. 1 def roll_emotion_chart
  148. 6 key = @randomizer.roll_once(6)
  149. 6 text = [
  150. "愛情/殺意",
  151. "友情/負目",
  152. "崇拝/嫌悪",
  153. "興味/侮蔑",
  154. "信頼/嫉妬",
  155. "守護/欲情",
  156. ][key - 1]
  157. 6 return "1D6 => [#{key}] #{text}"
  158. end
  159. 1 def roll_hope(number_of_dice)
  160. 11 total = 0
  161. 11 text = ""
  162. 11 loop do
  163. 20 d1 = @randomizer.roll_once(6)
  164. 20 d2 = 0
  165. 20 then: 10 else: 10 if number_of_dice >= 2
  166. 10 d2 = @randomizer.roll_once(6)
  167. end
  168. 20 total += d1 + d2
  169. 20 then: 10 if number_of_dice == 2
  170. 10 text += "2D6[#{d1},#{d2}]"
  171. else: 10 else
  172. 10 text += "1D6[#{d1}]"
  173. end
  174. 20 then: 9 if is_1or2(d1) || is_1or2(d2)
  175. 9 text += " (振り足し) => "
  176. else: 11 else
  177. 11 text += " => 合計 #{total}"
  178. 11 return text
  179. end
  180. end
  181. end
  182. 1 def is_1or2(n)
  183. 32 [1, 2].include?(n)
  184. end
  185. end
  186. end
  187. end

lib/bcdice/game_system/MagicaLogia.rb

98.91% lines covered

86.36% branches covered

92 relevant lines. 91 lines covered and 1 lines missed.
22 total branches, 19 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/base"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class MagicaLogia < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'MagicaLogia'
  8. # ゲームシステム名
  9. 1 NAME = 'マギカロギア'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'まきかろきあ'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・判定
  15. スペシャル/ファンブル/成功/失敗を判定
  16. ・各種表
  17. 経歴表 BGT/初期アンカー表 DAT/運命属性表 FAT
  18. 願い表 WIT/プライズ表 PT
  19. 時の流れ表 TPT/大判時の流れ表 TPTB
  20. 事件表 AT
  21. ファンブル表 FT/変調表 WT
  22. 運命変転表 FCT
  23.  典型的災厄 TCT/物理的災厄 PCT/精神的災厄 MCT/狂気的災厄 ICT
  24.  社会的災厄 SCT/超常的災厄 XCT/不思議系災厄 WCT/コミカル系災厄 CCT
  25.  魔法使いの災厄 MGCT
  26. シーン表 ST/大判シーン表 STB
  27.  極限環境 XEST/内面世界 IWST/魔法都市 MCST
  28.  死後世界 WDST/迷宮世界 LWST
  29.  魔法書架 MBST/魔法学院 MAST/クレドの塔 TCST
  30.  並行世界 PWST/終末   PAST/異世界酒場 GBST
  31.  ほしかげ SLST/旧図書館 OLST
  32. 世界法則追加表 WLAT/さまよう怪物表 WMT
  33. ランダム分野表 RCT
  34. ランダム特技表 RTT
  35.  星分野ランダム特技表 RTS, RTT1
  36.  獣分野ランダム特技表 RTB, RTT2
  37.  力分野ランダム特技表 RTF, RTT3
  38.  歌分野ランダム特技表 RTP, RTT4
  39.  夢分野ランダム特技表 RTD, RTT5
  40.  闇分野ランダム特技表 RTN, RTT6
  41. ブランク秘密表 BST/
  42.  宿敵表 MIT/謀略表 MOT/因縁表 MAT
  43.  奇人表 MUT/力場表 MFT/同盟表 MLT
  44. 落花表 FFT
  45. その後表 FLT
  46. ・D66ダイスあり
  47. INFO_MESSAGE_TEXT
  48. 1 def initialize(command)
  49. 465 super(command)
  50. 465 @sort_add_dice = true
  51. 465 @sort_barabara_dice = true
  52. 465 @d66_sort_type = D66SortType::ASC
  53. end
  54. # ゲーム別成功度判定(2D6)
  55. 1 def result_2d6(total, dice_total, dice_list, cmp_op, target)
  56. 21 then: 3 else: 18 return nil if target == '?'
  57. 18 else: 18 then: 0 return nil unless cmp_op == :>=
  58. result =
  59. 18 then: 3 if dice_total <= 2
  60. 3 else: 15 Result.fumble(translate("fumble"))
  61. 15 then: 3 elsif dice_total >= 12
  62. 3 else: 12 Result.critical(translate("MagicaLogia.special"))
  63. 12 then: 6 elsif total >= target
  64. 6 Result.success(translate("success"))
  65. else: 6 else
  66. 6 Result.failure(translate("failure"))
  67. end
  68. 18 result.text += gain_magic_element(dice_list[0], dice_list[1])
  69. 18 return result
  70. end
  71. 1 def eval_game_system_specific_command(command)
  72. 444 self.class::SKILL_TABLE.roll_command(@randomizer, command) ||
  73. roll_tables(command, self.class::TABLES)
  74. end
  75. 1 private
  76. # 魔素獲得チェック
  77. 1 def gain_magic_element(dice1, dice2)
  78. 18 else: 12 then: 6 return "" unless dice1 == dice2
  79. 12 element = translate("MagicaLogia.elements.items")[dice1 - 1]
  80. 12 return " > " + format(translate("MagicaLogia.elements.format"), text: element)
  81. end
  82. 1 class SkillExpandTable
  83. 1 def self.from_i18n(key, locale, skill_table)
  84. 66 table = I18n.t(key, locale: locale, raise: false)
  85. 66 new(table[:name], table[:type], table[:items], skill_table)
  86. end
  87. 1 def initialize(name, type, items, skill_table)
  88. 66 @name = name
  89. 66 @items = items.freeze
  90. 66 @skill_table = skill_table
  91. 66 m = /(\d+)D(\d+)/i.match(type)
  92. 66 else: 66 then: 0 unless m
  93. raise ArgumentError, "Unexpected table type: #{type}"
  94. end
  95. 66 @times = m[1].to_i
  96. 66 @sides = m[2].to_i
  97. end
  98. 1 def roll(randomizer)
  99. 234 value = randomizer.roll_sum(@times, @sides)
  100. 234 text = expand(@items[value - @times], randomizer)
  101. 234 return DiceTable::RollResult.new(@name, value, text)
  102. end
  103. 1 private
  104. 1 def expand(chosen, randomizer)
  105. 234 chosen.gsub(/%{([a-z]+)}/) do
  106. 124 m = Regexp.last_match
  107. 124 type = m[1].to_sym
  108. 124 roll_skill(type, randomizer)
  109. end
  110. end
  111. 1 CATEGORIES = [:star, :beast, :force, :poem, :dream, :night].freeze
  112. 1 def roll_skill(type, randomizer)
  113. 124 then: 82 else: 42 if type == :skill
  114. 82 return @skill_table.roll_skill(randomizer)
  115. end
  116. 42 then: 9 else: 33 if type == :element
  117. 9 return @skill_table.roll_category(randomizer)
  118. end
  119. 33 index = CATEGORIES.index(type)
  120. 33 else: 33 then: 0 raise ArgumentError unless index
  121. 33 @skill_table.categories[index].roll(randomizer).name
  122. end
  123. end
  124. 1 class FallenAfterTable
  125. 1 def self.from_i18n(key, locale)
  126. 3 table = I18n.t(key, locale: locale, raise: true)
  127. 3 new(table[:name], table[:items_lower], table[:items_higher])
  128. end
  129. 1 def initialize(name, items_lower, items_higher)
  130. 3 @name = name
  131. 3 @lower = items_lower
  132. 3 @higher = items_higher
  133. end
  134. 1 def roll(randomizer)
  135. 12 val1, val2 = randomizer.roll_barabara(2, 6)
  136. 12 then: 6 else: 6 table = val1 <= 3 ? @lower : @higher
  137. 12 "#{@name}(#{val1},#{val2}) > #{table[val2 - 1]}"
  138. end
  139. end
  140. 1 class << self
  141. 1 private
  142. 1 def translate_skill_table(locale)
  143. 3 DiceTable::SaiFicSkillTable.from_i18n(
  144. "MagicaLogia.skill_table",
  145. locale,
  146. rttn: ["RTS", "RTB", "RTF", "RTP", "RTD", "RTN"]
  147. )
  148. end
  149. 1 def translate_tables(locale, skill_table)
  150. 3 inveterate_enemy_table = SkillExpandTable.from_i18n("MagicaLogia.inveterate_enemy_table", locale, skill_table)
  151. 3 conspiracy_table = DiceTable::Table.from_i18n("MagicaLogia.conspiracy_table", locale)
  152. 3 fate_table = DiceTable::Table.from_i18n("MagicaLogia.fate_table", locale)
  153. 3 cueball_table = DiceTable::Table.from_i18n("MagicaLogia.cueball_table", locale)
  154. 3 force_field_table = DiceTable::Table.from_i18n("MagicaLogia.force_field_table", locale)
  155. 3 alliance_table = SkillExpandTable.from_i18n("MagicaLogia.alliance_table", locale, skill_table)
  156. {
  157. 3 "TPT" => SkillExpandTable.from_i18n("MagicaLogia.tables.TPT", locale, skill_table),
  158. "ST" => SkillExpandTable.from_i18n("MagicaLogia.tables.ST", locale, skill_table),
  159. "FT" => DiceTable::Table.from_i18n("MagicaLogia.tables.FT", locale),
  160. "WT" => SkillExpandTable.from_i18n("MagicaLogia.tables.WT", locale, skill_table),
  161. "FCT" => DiceTable::Table.from_i18n("MagicaLogia.tables.FCT", locale),
  162. "AT" => SkillExpandTable.from_i18n("MagicaLogia.tables.AT", locale, skill_table),
  163. "BGT" => DiceTable::Table.from_i18n("MagicaLogia.tables.BGT", locale),
  164. "DAT" => DiceTable::Table.from_i18n("MagicaLogia.tables.DAT", locale),
  165. "FAT" => DiceTable::Table.from_i18n("MagicaLogia.tables.FAT", locale),
  166. "WIT" => DiceTable::Table.from_i18n("MagicaLogia.tables.WIT", locale),
  167. "TCT" => DiceTable::Table.from_i18n("MagicaLogia.tables.TCT", locale),
  168. "PCT" => DiceTable::Table.from_i18n("MagicaLogia.tables.PCT", locale),
  169. "MCT" => DiceTable::Table.from_i18n("MagicaLogia.tables.MCT", locale),
  170. "ICT" => DiceTable::Table.from_i18n("MagicaLogia.tables.ICT", locale),
  171. "SCT" => DiceTable::Table.from_i18n("MagicaLogia.tables.SCT", locale),
  172. "XCT" => DiceTable::Table.from_i18n("MagicaLogia.tables.XCT", locale),
  173. "WCT" => DiceTable::Table.from_i18n("MagicaLogia.tables.WCT", locale),
  174. "CCT" => DiceTable::Table.from_i18n("MagicaLogia.tables.CCT", locale),
  175. "MIT" => inveterate_enemy_table,
  176. "MOT" => conspiracy_table,
  177. "MAT" => fate_table,
  178. "MUT" => cueball_table,
  179. "MFT" => force_field_table,
  180. "MLT" => alliance_table,
  181. "BST" => DiceTable::ChainTable.new(
  182. I18n.translate("MagicaLogia.tables.BST.name", raise: true, locale: locale),
  183. "1D6",
  184. [
  185. inveterate_enemy_table,
  186. conspiracy_table,
  187. fate_table,
  188. cueball_table,
  189. force_field_table,
  190. alliance_table,
  191. ]
  192. ),
  193. "PT" => DiceTable::Table.from_i18n("MagicaLogia.tables.PT", locale),
  194. "XEST" => SkillExpandTable.from_i18n("MagicaLogia.tables.XEST", locale, skill_table),
  195. "IWST" => SkillExpandTable.from_i18n("MagicaLogia.tables.IWST", locale, skill_table),
  196. "MCST" => SkillExpandTable.from_i18n("MagicaLogia.tables.MCST", locale, skill_table),
  197. "WDST" => SkillExpandTable.from_i18n("MagicaLogia.tables.WDST", locale, skill_table),
  198. "LWST" => SkillExpandTable.from_i18n("MagicaLogia.tables.LWST", locale, skill_table),
  199. "STB" => SkillExpandTable.from_i18n("MagicaLogia.tables.STB", locale, skill_table),
  200. "MGCT" => DiceTable::Table.from_i18n("MagicaLogia.tables.MGCT", locale),
  201. "MBST" => SkillExpandTable.from_i18n("MagicaLogia.tables.MBST", locale, skill_table),
  202. "MAST" => SkillExpandTable.from_i18n("MagicaLogia.tables.MAST", locale, skill_table),
  203. "TCST" => SkillExpandTable.from_i18n("MagicaLogia.tables.TCST", locale, skill_table),
  204. "PWST" => SkillExpandTable.from_i18n("MagicaLogia.tables.PWST", locale, skill_table),
  205. "PAST" => SkillExpandTable.from_i18n("MagicaLogia.tables.PAST", locale, skill_table),
  206. "GBST" => SkillExpandTable.from_i18n("MagicaLogia.tables.GBST", locale, skill_table),
  207. "SLST" => SkillExpandTable.from_i18n("MagicaLogia.tables.SLST", locale, skill_table),
  208. "WLAT" => DiceTable::Table.from_i18n("MagicaLogia.tables.WLAT", locale),
  209. "WMT" => SkillExpandTable.from_i18n("MagicaLogia.tables.WMT", locale, skill_table),
  210. "FFT" => DiceTable::Table.from_i18n("MagicaLogia.tables.FFT", locale),
  211. "OLST" => SkillExpandTable.from_i18n("MagicaLogia.tables.OLST", locale, skill_table),
  212. "TPTB" => SkillExpandTable.from_i18n("MagicaLogia.tables.TPTB", locale, skill_table),
  213. "FLT" => FallenAfterTable.from_i18n("MagicaLogia.tables.FLT", locale),
  214. }
  215. end
  216. end
  217. 1 SKILL_TABLE = translate_skill_table(:ja_jp)
  218. 1 TABLES = translate_tables(:ja_jp, SKILL_TABLE)
  219. 1 register_prefix(SKILL_TABLE.prefixes)
  220. 1 register_prefix(TABLES.keys)
  221. end
  222. end
  223. end

lib/bcdice/game_system/MagicaLogia_Korean.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/MagicaLogia"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class MagicaLogia_Korean < MagicaLogia
  6. # ゲームシステムの識別子
  7. 1 ID = "MagicaLogia:Korean"
  8. # ゲームシステム名
  9. 1 NAME = "마기카로기아"
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = "国際化:Korean:마기카로기아"
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・판정
  15. 스페셜/펌블/성공/실패
  16. ・각종 표
  17. 경력 표 BGT/ 초기 앵커 표 DAT/ 운명 속성 표 FAT
  18. 소원 표 WIT/ 프라이즈 표 PT
  19. 시간의 흐름 표(구판) TPT/ 대형판 시간의 흐름 표 TPTB
  20. 사건 표 AT
  21. 펌블 표 FT/ 상태이상 표 WT
  22. 운명 변전 표 FCT
  23.  전형적 재액 TCT/물리계 재액 PCT/정신계 재액 MCT/광기계 재액 ICT
  24.  사회계 재액 SCT/초자연계 재액 XCT/불가사의계 재액 WCT/코믹계 재액 CCT
  25.  마법사 재액 MGCT
  26. 장면표 ST/대형판 장면표 STB
  27.  극한 환경 XEST/내면 세계 IWST/마법 도시 MCST
  28.  사후 세계 WDST/미궁 세계 LWST
  29.  마법 서가 MBST/마법 학원 MAST/크레도의 탑 TCST
  30.  병행 세계 PWST/종말 PAST/이세계 술집 GBST
  31.  별빛 SLST/구 도서관 OLST
  32. 세계 법칙 추가 표 WLAT/떠돌이 괴물 표 WMT
  33. 랜덤 분야 표 RCT
  34. 랜덤 특기 표 RTT
  35.  별 분야 랜덤 특기 표 RTS, RTT1
  36.  짐승 분야 랜덤 특기 표 RTB, RTT2
  37.  힘 분야 랜덤 특기 표 RTF, RTT3
  38.  노래 분야 랜덤 특기 표 RTP, RTT4
  39.  꿈 분야 랜덤 특기 표 RTD, RTT5
  40.  어둠 분야 랜덤 특기 표 RTN, RTT6
  41. 백지 비밀 표 BST/
  42.  숙적표 MIT/모략 표 MOT/인연 표 MAT
  43.  기인표 MUT/역장 표 MFT/동맹 표 MLT
  44. 낙화 표 FFT
  45. 그 후의 전개 표 FLT
  46. ・D66 다이스 있음.
  47. INFO_MESSAGE_TEXT
  48. 1 register_prefix_from_super_class()
  49. 1 def initialize(command)
  50. 155 super(command)
  51. 155 @locale = :ko_kr
  52. end
  53. 1 SKILL_TABLE = translate_skill_table(:ko_kr)
  54. 1 TABLES = translate_tables(:ko_kr, SKILL_TABLE)
  55. end
  56. end
  57. end

lib/bcdice/game_system/MagicaLogia_SimplifiedChinese.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/MagicaLogia"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class MagicaLogia_SimplifiedChinese < MagicaLogia
  6. # ゲームシステムの識別子
  7. 1 ID = "MagicaLogia:SimplifiedChinese"
  8. # ゲームシステム名
  9. 1 NAME = "魔导书大战"
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = "国際化:Simplified Chinese:魔导书大战"
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・判定
  15. 可以判定大成功/大失败/成功/失败
  16. ・各种表
  17. 经历表 BGT/初期锚点表 DAT/命运属性表 FAT
  18. 愿望表 WIT/战利品表 PT
  19. 时间流逝表 TPT/大判时间流逝表 TPTB
  20. 事件表 AT
  21. 大失败表 FT/变调表 WT
  22. 命运转变表表 FCT
  23.  典型性灾厄 TCT/物理性灾厄 PCT/精神性灾厄 MCT/狂气性灾厄 ICT
  24.  社会性灾厄 SCT/超自然灾厄 XCT/不可思议的灾厄 WCT/喜剧性灾厄 CCT
  25.  魔法使的灾厄 MGCT
  26. 场景表 ST/大判场景表 STB
  27.  极限环境 XEST/内心世界 IWST/魔法都市 MCST
  28.  死后世界 WDST/迷宫世界 LWST
  29.  魔法书架 MBST/魔法学院 MAST/克雷德塔 TCST
  30.  平行世界 PWST/终末世界 PAST/异世界酒吧 GBST
  31.  星影 SLST/旧图书馆 OLST
  32. 世界法则追加表 WLAT/徘徊怪物表 WMT
  33. 随机领域表 RCT
  34. 随机特技表 RTT
  35.  星领域随机特技表 RTS, RTT1
  36.  兽领域随机特技表 RTB, RTT2
  37.  力领域随机特技表 RTF, RTT3
  38.  歌领域随机特技表 RTP, RTT4
  39.  梦领域随机特技表 RTD, RTT5
  40.  暗领域随机特技表 RTN, RTT6
  41. 空白秘密表 BST
  42.  宿敌表 MIT/谋略表 MOT/因缘表 MAT
  43.  奇人表 MUT/力场表 MFT/同盟表 MLT
  44. 落花表 FFT
  45. 那之后表 FLT
  46. ・可以使用D66
  47. INFO_MESSAGE_TEXT
  48. 1 register_prefix_from_super_class()
  49. 1 def initialize(command)
  50. 155 super(command)
  51. 155 @locale = :zh_hans
  52. end
  53. 1 SKILL_TABLE = translate_skill_table(:zh_hans)
  54. 1 TABLES = translate_tables(:zh_hans, SKILL_TABLE)
  55. end
  56. end
  57. end

lib/bcdice/game_system/Magius.rb

98.15% lines covered

87.5% branches covered

54 relevant lines. 53 lines covered and 1 lines missed.
16 total branches, 14 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Magius < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Magius'
  7. # ゲームシステム名
  8. 1 NAME = 'MAGIUS'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'まきうす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGETEXT
  13. ■能力値判定 MA+x>=t x:修正値 t:目標値
  14. 例)MA>=7: ダイスを2個振って、その結果を表示
  15. ■技能値判定 MS+x>=t x:修正値 t:目標値
  16. 例)MS>=7: ダイスを3個振って、そのうち上位2つを採用し、結果を表示
  17. INFO_MESSAGETEXT
  18. 1 register_prefix('M[AS]')
  19. 1 def initialize(command)
  20. 16 super(command)
  21. 16 @sort_barabara_dice = true # バラバラロール(Bコマンド)でソート有
  22. end
  23. 1 def eval_game_system_specific_command(command)
  24. 16 resolute_ability_action(command) ||
  25. resolute_skill_action(command)
  26. end
  27. 1 private
  28. 1 def with_symbol(number)
  29. 16 then: 12 if number == 0
  30. 12 else: 4 return ""
  31. 4 then: 4 elsif number > 0
  32. 4 return "+#{number}"
  33. else: 0 else
  34. return number.to_s
  35. end
  36. end
  37. # 能力値判定
  38. # @param [String] command
  39. # @return [Result]
  40. 1 def get_result_of_ability_action(total, _dice_add, target)
  41. 3 then: 2 if total >= target
  42. 2 return Result.success("成功")
  43. else: 1 else
  44. 1 return Result.failure("失敗")
  45. end
  46. end
  47. 1 def resolute_ability_action(command)
  48. 16 m = /MA([+-]\d+)*>=(\d+)/.match(command)
  49. 16 else: 8 then: 8 return nil unless m
  50. 8 then: 2 else: 6 modify = m[1] ? Arithmetic.eval(m[1], @round_type) : 0
  51. 8 target = m[2].to_i
  52. 8 dices = @randomizer.roll_barabara(2, 6).sort
  53. 8 dice_text = dices.join(",")
  54. 8 dice_add = dices.sum
  55. 8 total = dice_add + modify
  56. 8 result = get_result_of_ability_action(total, dice_add, target)
  57. sequence = [
  58. 8 "(#{command})",
  59. "[#{dice_text}]#{with_symbol(modify)}",
  60. total,
  61. result.text,
  62. ].compact
  63. 8 result.text = sequence.join(" > ")
  64. 8 return result
  65. end
  66. # 技能値値判定
  67. # @param [String] command
  68. # @return [Result]
  69. 1 def get_result_of_skill_action(total, _dice_add, target)
  70. 3 then: 2 if total >= target
  71. 2 return Result.success("成功")
  72. else: 1 else
  73. 1 return Result.failure("失敗")
  74. end
  75. end
  76. 1 def resolute_skill_action(command)
  77. 8 m = /MS([+-]\d+)*>=(\d+)/.match(command)
  78. 8 else: 8 then: 0 return nil unless m
  79. 8 then: 2 else: 6 modify = m[1] ? Arithmetic.eval(m[1], @round_type) : 0
  80. 8 target = m[2].to_i
  81. 8 dices = @randomizer.roll_barabara(3, 6).sort
  82. 8 dice_text = dices.join(",")
  83. 8 dice_add = dices[1].to_i + dices[2].to_i
  84. 8 total = dice_add + modify
  85. 8 result = get_result_of_skill_action(total, dice_add, target)
  86. sequence = [
  87. 8 "(#{command})",
  88. "[#{dice_text}]#{with_symbol(modify)}",
  89. total,
  90. result.text,
  91. ].compact
  92. 8 result.text = sequence.join(" > ")
  93. 8 return result
  94. end
  95. end
  96. end
  97. end

lib/bcdice/game_system/Magius_3rdNewTokyoCity.rb

100.0% lines covered

100.0% branches covered

26 relevant lines. 26 lines covered and 0 lines missed.
12 total branches, 12 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/Magius'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Magius_3rdNewTokyoCity < Magius
  6. # ゲームシステムの識別子
  7. 1 ID = 'Magius_3rdNewTokyoCity'
  8. # ゲームシステム名
  9. 1 NAME = 'MAGIUS:新世紀エヴァンゲリオンRPG 決戦!第3新東京市'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'まきうすしんせいきえうあんけりおんRPGけつせんたい3しんとうきようし'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGETEXT
  14. ■能力値判定 MA+x>=t x:修正値 t:目標値
  15. 例)MA>=7: ダイスを2個振って、その結果(成功,失敗,絶対成功,絶対失敗)を表示
  16. ■技能値判定 MS+x>=t x:修正値 t:目標値
  17. 例)MS>=7: ダイスを3個振って、そのうち上位2つを採用し、結果(成功,失敗,絶対成功,絶対失敗)を表示
  18. INFO_MESSAGETEXT
  19. 1 register_prefix('M[AS]')
  20. 1 private
  21. # 能力値判定の結果取得
  22. # @param [Integer] total, dice_add, target
  23. # @return [Result]
  24. 1 def get_result_of_ability_action(total, dice_add, target)
  25. 5 then: 1 if dice_add == 12
  26. 1 else: 4 return Result.critical("絶対成功")
  27. 4 then: 1 elsif dice_add == 2
  28. 1 else: 3 return Result.fumble("絶対失敗")
  29. 3 then: 2 elsif total >= target
  30. 2 return Result.success("成功")
  31. else: 1 else
  32. 1 return Result.failure("失敗")
  33. end
  34. end
  35. # 技能値判定の結果取得
  36. # @param [Integer] total, dice_add, target
  37. # @return [Result]
  38. 1 def get_result_of_skill_action(total, dice_add, target)
  39. 5 then: 1 if dice_add == 12
  40. 1 else: 4 return Result.critical("絶対成功")
  41. 4 then: 1 elsif dice_add == 2
  42. 1 else: 3 return Result.fumble("絶対失敗")
  43. 3 then: 2 elsif total >= target
  44. 2 return Result.success("成功")
  45. else: 1 else
  46. 1 return Result.failure("失敗")
  47. end
  48. end
  49. end
  50. end
  51. end

lib/bcdice/game_system/MamonoScramble.rb

100.0% lines covered

100.0% branches covered

35 relevant lines. 35 lines covered and 0 lines missed.
6 total branches, 6 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MamonoScramble < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'MamonoScramble'
  7. # ゲームシステム名
  8. 1 NAME = 'マモノスクランブル'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'まものすくらんふる'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定 xMS<=t
  14.  [判定]を行う。成否と[マリョク]の上昇量を表示する。
  15.  x: ダイス数
  16.  t: 能力値(目標値)
  17. ・アクシデント表 ACC
  18. INFO_MESSAGE_TEXT
  19. 1 def initialize(command)
  20. 14 super(command)
  21. 14 @sides_implicit_d = 12
  22. 14 @round_type = RoundType::CEIL
  23. end
  24. 1 def eval_game_system_specific_command(command)
  25. 14 roll_ability(command) || roll_tables(command, TABLES)
  26. end
  27. 1 private
  28. 1 def roll_ability(command)
  29. 14 parser = Command::Parser.new("MS", round_type: @round_type)
  30. .has_prefix_number
  31. .disable_modifier
  32. .restrict_cmp_op_to(:<=)
  33. 14 parsed = parser.parse(command)
  34. 14 else: 11 then: 3 unless parsed
  35. 3 return nil
  36. end
  37. 11 dice_list = @randomizer.roll_barabara(parsed.prefix_number, 12).sort
  38. 31 count_success = dice_list.count { |value| value <= parsed.target_number }
  39. 11 count_one = dice_list.count(1)
  40. 11 is_critical = count_one > 0
  41. 11 has_twelve = dice_list.include?(12)
  42. maryoku =
  43. 11 then: 2 if has_twelve && !is_critical
  44. 2 0
  45. else: 9 else
  46. 9 count_success + count_one
  47. end
  48. sequence = [
  49. 11 "(#{parsed})",
  50. "[#{dice_list.join(',')}]",
  51. 11 then: 9 else: 2 count_success > 0 ? "成功, [マリョク]が#{maryoku}上がる" : "失敗"
  52. ]
  53. 11 return Result.new.tap do |r|
  54. 11 r.text = sequence.join(" > ")
  55. 11 r.condition = count_success > 0
  56. 11 r.critical = r.success? && is_critical
  57. end
  58. end
  59. TABLES = {
  60. 1 "ACC" => DiceTable::Table.new(
  61. "アクシデント表",
  62. "1D12",
  63. [
  64. "思わぬ対立:[判定]で10〜12の出目を1個でも出した場合、【耐久値】を2点減らす。",
  65. "都市の迷宮化:[判定]に【社会】を使用できない。",
  66. "不穏な天気:特別な効果は発生しない。",
  67. "突然の雷雨:エリアの[特性]に[雨]や[水たまり]などを足してもいい。",
  68. "関係ない危機:[判定]に失敗したPCの【耐久値】を2点減らす。",
  69. "からりと晴天:エリアの[特性]に[強い日光]や[日だまり]などを足してもいい。",
  70. "謎のお祭り:[判定]で1〜3の出目を1個でも出した場合、【耐久値】を2点回復する。",
  71. "すごい人ごみ:エリアの[特性]に[野次馬]や[観光客]などを足してもいい。",
  72. "マリョク乱気流:[判定]に【異質】を使用できない。",
  73. "魔術テロ事件:GMが1Dをロールする。出目が1〜3なら【身体】、出目が4〜6なら【異質】、出目が7〜9なら【社会】が[判定]で使えない。10〜12は何も起きない。",
  74. "マリョク低気圧:[判定]に【身体】を使用できない。",
  75. "平穏な時間:特別な効果は発生しない。",
  76. ]
  77. )
  78. }.freeze
  79. 1 register_prefix('\d+MS', TABLES.keys)
  80. end
  81. end
  82. end

lib/bcdice/game_system/MeikyuDays.rb

95.38% lines covered

83.33% branches covered

65 relevant lines. 62 lines covered and 3 lines missed.
30 total branches, 25 branches covered and 5 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MeikyuDays < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'MeikyuDays'
  7. # ゲームシステム名
  8. 1 NAME = '迷宮デイズ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'めいきゆうていす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定 (nMD+m)
  14.  n個のD6を振って大きい物二つだけみて達成値を算出します。修正mも可能です。
  15.  絶対成功と絶対失敗も自動判定します。
  16. ・各種表
  17.  ・散策表      DRT
  18.  ・交渉表      DNT
  19.  ・休憩表      DBT
  20.  ・ハプニング表   DHT
  21.  ・カーネル停止表  KST
  22.  ・痛打表 CAT/戦闘ファンブル表 CFT/致命傷表 FWT
  23.  ・おたから表1/2/3/4 T1T/T2T/T3T/T4T
  24.  ・相場表      MPT
  25.  ・登場表      APT
  26.  ・因縁表 DCT/怪物因縁表 MCT/PC因縁表 PCT/ラブ因縁表 LCT
  27. ・D66ダイスあり
  28. INFO_MESSAGE_TEXT
  29. 1 def initialize(command)
  30. 229 super(command)
  31. 229 @sort_add_dice = true
  32. 229 @d66_sort_type = D66SortType::ASC
  33. end
  34. 1 def replace_text(string)
  35. 40 string = string.gsub(/(\d+)MD6/i) { "#{Regexp.last_match(1)}R6" }
  36. 80 string = string.gsub(/(\d+)MD/i) { "#{Regexp.last_match(1)}R6" }
  37. 40 return string
  38. end
  39. 1 def result_2d6(total, dice_total, _dice_list, cmp_op, target)
  40. 19 else: 19 then: 0 return nil unless cmp_op == :>=
  41. 19 then: 2 if dice_total <= 2
  42. 2 else: 17 Result.fumble("絶対失敗")
  43. 17 then: 2 elsif dice_total >= 12
  44. 2 else: 15 Result.critical("絶対成功")
  45. 15 then: 1 elsif target == "?"
  46. 1 else: 14 Result.nothing
  47. 14 then: 12 elsif total >= target
  48. 12 Result.success("成功")
  49. else: 2 else
  50. 2 Result.failure("失敗")
  51. end
  52. end
  53. 1 def checkRoll(string)
  54. 40 string = replace_text(string)
  55. 40 debug("checkRoll string", string)
  56. 40 else: 40 then: 0 unless (m = /(^|\s)S?((\d+)[rR]6([+\-\d]*)(([>=]+)(\d+))?)(\s|$)/i.match(string))
  57. debug("not mutch")
  58. return nil
  59. end
  60. 40 string = m[2]
  61. 40 dice_c = m[3].to_i
  62. 40 bonus = 0
  63. 40 signOfInequality = ""
  64. 40 diff = 0
  65. 40 bonusText = m[4]
  66. 40 else: 0 then: 40 bonus = ArithmeticEvaluator.eval(bonusText) unless bonusText.nil?
  67. 40 then: 10 else: 30 signOfInequality = m[6] if m[6]
  68. 40 then: 10 else: 30 diff = m[7].to_i if m[7]
  69. 40 dice_num = @randomizer.roll_barabara(dice_c, 6).sort
  70. 40 dice_str = dice_num.join(",")
  71. 40 dice_now = dice_num[dice_c - 2] + dice_num[dice_c - 1]
  72. 40 total_n = dice_now + bonus
  73. 40 dice_str = "[#{dice_str}]"
  74. 40 output = "#{dice_now}#{dice_str}"
  75. 40 then: 30 if bonus > 0
  76. 30 else: 10 output += "+#{bonus}"
  77. 10 then: 0 else: 10 elsif bonus < 0
  78. output += bonus.to_s
  79. end
  80. 40 then: 30 if /[^\d\[\]]+/ =~ output
  81. 30 output = "(#{string}) > #{output} > #{total_n}"
  82. else: 10 else
  83. 10 output = "(#{string}) > #{total_n}"
  84. end
  85. 40 then: 10 else: 30 if signOfInequality != "" # 成功度判定処理
  86. 10 cmp_op = Normalize.comparison_operator(signOfInequality)
  87. 10 result = result_2d6(total_n, dice_now, dice_num, cmp_op, diff)
  88. 10 then: 10 else: 0 output += " > #{result.text}" if result
  89. end
  90. 40 return output
  91. end
  92. #################### 迷宮デイズ ########################
  93. 1 def eval_game_system_specific_command(command)
  94. 220 then: 180 if (result = roll_tables(command, TABLES))
  95. 180 result
  96. else: 40 else
  97. 40 checkRoll(command)
  98. end
  99. end
  100. TABLES = {
  101. 1 "DRT" => DiceTable::Table.new(
  102. "散策表",
  103. "2D6",
  104. [
  105. '次に挑む迷宮の迷宮支配者を倒さなければ人類文明が滅ぶことを偶然知ってしまう。《気力》を最大値まで回復する。',
  106. '同じ迷宮を対象とする違う依頼を受ける。シナリオの目的を果たしたときに、追加で1d6MCの報酬を得られるようになる。',
  107. '他の迷宮屋の評判を耳にする。パーティから好きなキャラクター1人を選び、そのキャラクターに対する《好意》が1点上昇する。',
  108. '毎日の散歩の成果が出て、体の調子が良い。このゲーム中、《HP》の最大値が5点上昇し、《HP》が5点回復する。',
  109. 'メディアの取材を受ける。《民の声》を2点得る。',
  110. '近所からおすそ分けをもらう。【回復薬】を6個手に入れる。',
  111. '近所の人がきみの噂話をしている。ゲーム中に自分が対象に入った「恋人」「親友」「忠誠」の人間関係を成立させるたび、《民の声》を2点得る。',
  112. '似たような迷宮に挑んだことがある迷宮屋から話を聞いた。迷宮フェイズでの情報収集の難易度が2下がる。',
  113. '武具の安売りを見つける。ランダムな武具アイテム1つを半分の値段で購入することができる。',
  114. '他の迷宮屋と喧嘩になる。パーティの中からランダムに1人を選び、お互いの《敵意》を1点上昇させる。',
  115. '迷宮屋志望の見習が、1d6人ほど配下として加わる。',
  116. ]
  117. ),
  118. "DBT" => DiceTable::Table.new(
  119. "休憩表",
  120. "2D6",
  121. [
  122. 'アイテムの改善案を出し合ってみる。各キャラクターは、好きなキャラクター1体を選び、1d6を振ってそのキャラクターのアイテムスロットから1つをランダムに選ぶ。出た目のアイテムにレベルがあれば、1上昇する。',
  123. '何気ない雑談が腹の探り合いに発展する。各キャラクターは、好きなキャラクターに対する《好意》と《敵意》を入れ替え、その属性を自由に変更することができる。',
  124. '好きな単語表からランダムに単語を1つ選ぶ。その部屋にはそれに関係したものがたくさん置いてあるため、出た単語が「好きなもの」に入っているキャラクターは、《気力》を2点得る。',
  125. '嫌いな人の話題で盛り上がる。各キャラクターは同じキャラクターに《敵意》を持っている人を1人選び、その人への《好意》を1点上昇させる。',
  126. '窓の外から報道のヘリコプターがこちらを撮影しているのが見える。格好よく見せるために、各キャラクターは〔魅力〕で難易度13の判定を行う。誰かが成功するたびに《民の声》が1点増加する。',
  127. '雑談や休息など、思い思いに時間を過ごす。各キャラクターは、好きなキャラクター1体への《好意》を1点上昇させる。',
  128. '通路の片隅で素材が山を作っているのを見つけた。各キャラクターは〔探索〕で難易度11の判定を行う。誰かが成功するたびに、好きな素材を1種類選び、それを1d6個手に入れる。',
  129. 'チームワークの確認。各プレイヤーは打ち合わせをせずに、一斉にじゃんけんを行う。いちばん出した人が多かった手を出したプレイヤーのPCは、《気力》を2点得る。',
  130. '仮眠をとって休憩。各キャラクターは〔才覚〕で難易度9の判定を行う。成功すれば《HP》が最大値まで回復する。',
  131. '各キャラクターは、迷宮化現象に巻き込まれ、身動きがとれない普通の人を1人見つけた。《配下》に加えることができる。',
  132. '各キャラクターは1d6を振る。出た目の上位2名が唐突に恋に落ちる。同じ目が出て2名をうまく割り出せない場合は、GMの左隣に近い方を優先する。恋に落ちた2人、相手以外に対する《好意》を合計し、その値に対する《好意》に加える。その後、相手以外に対する《好意》をすべて0にする。',
  133. ]
  134. ),
  135. "DNT" => DiceTable::Table.new(
  136. "交渉表",
  137. "2D6",
  138. [
  139. '中立的な態度は偽装だった。彼らは不意打ちを行う。奇襲扱いで戦闘を開始すること。',
  140. '交渉は決裂! 戦闘を行うこと。',
  141. '交渉は決裂! 戦闘を行うこと。',
  142. '「贄をささげれば話を聞こう」モンスターの中で最もレベルが高いもののレベルと等しい数だけ何らかの素材を減少すれば、友好的になる。減少させない場合、戦闘を開始すること。',
  143. '「……お前の趣味、なに?」好きな単語表一個を選び、D66を振る。パーティの中に、その項目を好きなものにしているキャラクターがいれば、友好的になる。そうでなければ戦闘を開始すること。',
  144. '怪物たちは物欲しそうにこちらを見ている。「肉」の素材をモンスターの数だけ消費するか、【お弁当】【フルコース】1個を消費すれば友好的になる。消費しなければ、戦闘を開始すること。',
  145. '怪物たちは値踏みするようにこちらを見ている。現金で1d6MC支払えば友好的になる。そうでない場合、戦闘を開始すること。',
  146. '「何かいいもんよこせ」モンスターの中で最もレベルの高いもののレベル以上の価格のアイテムを消費すれば友好的になる。そうでない場合、戦闘を開始すること。',
  147. '「面白い話を聞かせろよ」プレイヤーたちは面白い話をすること。GMは面白いと思えばモンスターは友好的になる。面白くなかった場合は戦闘を開始する。',
  148. '「俺に勝てたら話を聞いてやろう」怪物が力比べを挑んできた。モンスターの中で最もレベルが高いものと、パーティの代表がそれぞれ〔武勇〕で判定を行う。パーティの代表の達成値がモンスター以上であれば友好的になる。負けた場合、もう一度交渉するか戦闘するかを決定すること。',
  149. '運命の出会い。一目見た瞬間に打ち解けあい、友好的になる。',
  150. ]
  151. ),
  152. "DHT" => DiceTable::Table.new(
  153. "ハプニング表",
  154. "2D6",
  155. [
  156. '急に絶望に襲われる。【お酒】を消費することが出来なければ、このゲーム中、最も高い能力値が1点減少する。',
  157. '思考に靄がかかってしまう。「散漫」のバッドステータスを受ける。',
  158. '気がついたら太っていた。「肥満」のバッドステータスを受ける。',
  159. '無残な失敗に愛想を尽かした配下が2d6人ほど去って行ってしまう。',
  160. '微妙な空気を読み切れず、パーティ全員の《気力》が1点減少する。',
  161. '事故だか故意だかで、仲間を殴ってしまう。ランダムに選んだパーティメンバー1名の《HP》を自分の〔武勇〕と同じ値だけ減少させる。',
  162. '期待が大きければ失望も大きい。あなたに対して《好意》を持っているキャラクター全員は、あなたに対する《好意》を1点減らす。',
  163. 'アイテムを粗末に扱ってしまう。持ち物の中からランダムにアイテムを1つ決定する。そのアイテムにレベルがある場合、レベルが1下がる。',
  164. '失敗のショックのせいで知的な行動をとれなくなる。「愚か」のバッドステータスを受ける。',
  165. '過去の行状のせいで人に呪われる。「呪い」のバッドステータスを受ける。',
  166. '自分の失敗が許せない。このゲームの間、《器》が1点減少したものとして扱う。',
  167. ]
  168. ),
  169. "KST" => DiceTable::Table.new(
  170. "カーネル停止表",
  171. "2D6",
  172. [
  173. 'カーネルが肉体に致命的な迷宮化を引き起こす!致命傷表を振ること。カーネルはまだ停止しない。',
  174. '〔才覚〕で難易度9の判定を行う。失敗すると記憶が迷宮化を起こし、銀行口座の暗証番号を忘れてしまう。口座に入っているMCはすべて失われる。カーネルは停止しない。',
  175. '迷宮化エネルギーが装備を直撃。素早く避けるため〔武勇〕で難易度9の判定を行う。失敗した場合、持っているアイテムからランダムに1つを選ぶ。そのアイテムは激しい迷宮化を起こし破壊される。カーネルは停止しない。',
  176. '正体不明のエネルギーが部屋中を駆け巡る。パーティ全員は1d6ダメージを受ける。カーネルは停止しない。',
  177. '心象が迷宮化していく。〔魅力〕で難易度9の判定を行う。失敗すると人間関係が迷宮化を起こし、持っている感情値がすべて1点減少する。カーネルは停止しない。',
  178. '激しい迷宮化に曝され、1d6点のダメージを受ける。〔探索〕で難易度11の判定を行う。成功すれば、怪我を負いながらもカーネルを停止させることに成功する。',
  179. 'パーティ全員は軽い迷宮化に曝され1ダメージを受ける。パーティを統率する為に〔魅力〕で難易度11の判定を行うこと。成功すれば、カーネルは停止する。',
  180. '素早い一撃でカーネルの息の根を止めるために〔武勇〕で難易度9の判定を行う。成功すれば見事にカーネルを停止させることに成功する。',
  181. 'カーネルの構造を感じ取り、一瞬にして停止させることに成功。さらに迷宮化の副産物としてランダムなレアアイテム1つを入手する。',
  182. 'カーネルは停止した。そして持っているアイテムの中からランダムに1つを選ぶ。そのアイテムにレベルがあれば、いつのまにかレベルが1上昇している。',
  183. '鮮やかにカーネルを停止させ、傷一つないまま保存することに成功した。このカーネルの売却価格が3d6MC上昇する。',
  184. ]
  185. ),
  186. "CAT" => DiceTable::Table.new(
  187. "痛打表",
  188. "2D6",
  189. [
  190. '武器の伝説がまた一つ増えた。攻撃に使用した武具アイテムにレベルがあれば、そのレベルが1点上昇する。',
  191. '偶然ながら敵の弱点をつく。敵の《HP》を現在の半分の値にする。',
  192. '攻撃が終わった後、攻撃の勢いを利用して、自分を好きなエリアに移動させることができる。',
  193. '素晴らしい手ごたえに自分でも感動し、自分の《HP》が全快する。',
  194. '叙事詩的な一撃。《民の声》を1点増やす。',
  195. 'クリーンヒット。攻撃の威力が2d6点上昇する。',
  196. '敵の動きを封じた。攻撃目標の《回避値》を戦闘終了まで2下げる。この効果は累積する。',
  197. '敵の勢いを利用し大ダメージ。攻撃の威力が、攻撃目標のレベルと同じだけ上昇する。',
  198. '敵の技を封じる。攻撃目標のスキル1種類を選び、戦闘中はそのスキルを使用できなくする。',
  199. '敵の急所をとらえ致命傷を与える。攻撃目標の《HP》を0にする。',
  200. '戦いの中、武具もまた成長する。持っているアイテムをランダムに1選ぶ。そのアイテムにレベルがあれば、1点上昇する。',
  201. ]
  202. ),
  203. "FWT" => DiceTable::Table.new(
  204. "致命傷表",
  205. "2D6",
  206. [
  207. '重要器官を粉砕される。キャラクターは即座に死亡する。',
  208. '傍目にも分かる致命傷。キャラクターは次の自分の行動処理が終わった時点で死亡する。《HP》の回復でこの死亡を防ぐことはできない。',
  209. '全身に強い衝撃をうける。〔武勇〕で難易度[5+受けたダメージ]の判定に成功すると、行動不能になる。判定に失敗すると死亡する。',
  210. '出血多量で意識不明。行動不能になる。この戦闘が終了するまでに《HP》を1以上にしないと、キャラクターは死亡する。',
  211. '重傷を負い昏睡状態。行動不能になる。このクォーターが終了するまでに《HP》を1以上にしないと、キャラクターは死亡する。',
  212. '攻撃で負った傷により意識を失う。行動不能になる。',
  213. '緊急回避! 〔探索〕で難易度[7-現在の《HP》]の判定を行う。成功すると、ランダムなバッドステータス1つを受けたうえで攻撃が無効になる。失敗すると、ランダムなバッドステータス1つを受けたうえで行動不能になる。',
  214. '最後の一撃を見切ることができるかもしれない。〔才覚〕で難易度[9-現在の《HP》]の判定を行う。成功すると《HP》が1になる。失敗すると行動不能になる。',
  215. 'まだここで死ぬ運命ではないのかもしれない。〔魅力〕で難易度[9-現在の《HP》]の判定を行う。成功すると《HP》が1になる。失敗すると行動不能になる。',
  216. 'カウンター! 攻撃をしてきた敵に対して、割り込んで好きな武器またはスキルを使った反撃をすることができる。これらの判定が成功した場合、ダメージやスキルの効果のあとで《HP》が1になる。失敗した場合、ただ行動不能になる。',
  217. '致命傷を受けたような気がしたが、気のせいだった。',
  218. ]
  219. ),
  220. "CFT" => DiceTable::Table.new(
  221. "戦闘ファンブル表",
  222. "2D6",
  223. [
  224. 'ぶざまな失敗に熱くなる。攻撃の目標のキャラクターに対して《敵意》を4点得る。',
  225. '急にお腹が痛くなる! 何か回復アイテムを使うまで攻撃を行えなくなる。モンスターの場合、そのラウンドの終わりに未行動にならなくなる。',
  226. 'アイテムが壊れた! 自分が持っているアイテムの中からランダムに1つを選び、そのアイテムが失われる。モンスターの場合、1d6ダメージを受ける。',
  227. '敵がいい気になる。行動不能になっていない敵軍キャラクター全ての《HP》を6点回復する。',
  228. '自分に攻撃が命中! 使用した武器のダメージを自分に与える。',
  229. 'なんというか、やる気をなくす。《気力》を1点失う。モンスターの場合、1d6ダメージを受ける。',
  230. '仲間に攻撃が命中! 使用した武器の射程内の味方から、ランダムに1人を選ぶ。そのキャラクターに武器のダメージを与える。',
  231. '仲間の邪魔をしてしまう。未行動の自軍キャラクター1体を選び、行動済みにする。',
  232. 'スキルを忘れてしまった! 習得しているスキルからランダムに1種類を選ぶ。そのスキルは戦闘が終了するまで使用できない。',
  233. '位置取りに失敗してとんでもない場所に。敵陣営プレイヤーまたはGMが、ファンブルしたキャラクターを好きな位置に移す。',
  234. 'ピンチがチャンスに! 《HP》が現在値の半分になり、《気力》が最大値まで貯まる。',
  235. ]
  236. ),
  237. "APT" => DiceTable::Table.new(
  238. "登場表",
  239. "2D6",
  240. [
  241. '「ここから先に行かせるわけにはいかん」急ぐ途中に敵が立ちふさがる。〔武勇〕で難易度11の判定を行う。成功すればバトルフィールドの好きなエリアにそのキャラクターを配置することができる。失敗した場合、《HP》を1にした状態でバトルフィールドの好きなエリアにそのキャラクターを配置することができる。',
  242. '「待たせたな!」バトルフィールドの好きなエリアにそのキャラクターを配置することができる。',
  243. 'おっと鉢合わせ! バトルフィールドの敵軍の本陣に、そのキャラクターを配置すること。',
  244. '全力で駆けつける! 《HP》を2d6点減少すれば、バトルフィールドの好きなエリアにそのキャラクターを配置することができる。',
  245. 'あいつらはこの先に行ったはず! GMはそのキャラクターをバトルフィールドの好きなエリアに配置する。',
  246. 'あの聞き覚えのある音は……! そのキャラクターが【乗騎】を装備していれば、GMはそのキャラクターをバトルフィールドの好きなエリアに配置する。',
  247. '……間に合ったみたいだな。バトルフィールドの中に、そのキャラクターに対する《好意》が1点以上あるキャラクターがいれば、同じエリアにそのキャラクターを配置することができる。',
  248. 'を! これはこれは。好きな素材を1個拾う。',
  249. 'いかん! 迷ってしまった。〔探索〕で難易度11の判定を行うこと。成功すればもう一度登場表を振り、結果を適用することができる。',
  250. 'むむむむ? ここは一度来た道のような……? 疲労して《気力》が1点減少。',
  251. '……いや、しかしそれどころではない! そのキャラクターは、この戦闘に登場することはできない。',
  252. ]
  253. ),
  254. "DCT" => DiceTable::Table.new(
  255. "因縁表",
  256. "2D6",
  257. [
  258. '対象はあなたの父、もしくは母である。幼い頃に家庭を捨てて失踪した対象を、あなたはずっと憎んでいた。対象への《敵意》が1点上昇する。また、対象を戦闘で倒した際に、経験点10点を得ることができる。',
  259. '対象は、あなたの小学校時代の恩師である。懐かしい顔にこんな形で会うことになろうとは。対象への《好意》もしくは《敵意》が1点上昇する。',
  260. '対象は、過去にあなたと戦い、あなたの体に古傷を残している。今でもときどき傷は代償を求めて疼く。対象への《敵意》が1点上昇する。',
  261. 'あなたは対象に憧れているが、全く相手にされていない。たとえ敵としてでも対象に認めてもらうことがあなたの願いだ。彼または彼女への《敵意》が1点上昇し、「ライバル」の人間関係を結ぶことが出来れば経験点を10得られるようになる。',
  262. 'あなたは過去、対象のせいで、思い出したくもない大失敗をしたことがある。嫌いなものに絡んだ大失敗を設定すること。対象への《敵意》が1点上昇する。',
  263. 'あなたは対象に手酷く敗北したことがある。あなたは屈辱を晴らすためにできる限りのことをする気でいる。対象への《敵意》が1点上昇する。',
  264. '対象はあなたの親族を殺した。あなたはいつか訪れる復讐の日を信じて、鍛錬を続けてきた。対象への《敵意》が1点上昇する。',
  265. '対象は、過去のあなたの仲間だ。意見の違いで袂を分かったが、ここまで対立することになるとは考えてもいなかった。対象への《敵意》が1点上昇する。',
  266. '対象とあなたは、前世があなたの妻/夫であった。幸せな生涯の記憶が蘇る。対象への《好意》が1点上昇する。',
  267. 'あなたは対象とあなたの通勤・通学路でぶつかったことがあり、そこで一目惚れしている。恋を幸せに成就させるため、もしくは不幸な恋を対象の死によって終わらせるため、あなたは迷宮にめぐる。対象への愛情の《好意》4点と、「片思い」の人間関係を得る。',
  268. 'あなたは過去に対象の恋人であった。対象のどこが好きだったのかは、自分の好きなものからランダムに単語を決め、それに関連した話をでっち上げること。対象への愛情の《好意》4点と、「恋人」の人間関係を得る。',
  269. ]
  270. ),
  271. "MCT" => DiceTable::Table.new(
  272. "怪物因縁表",
  273. "2D6",
  274. [
  275. '対象はあなたの故郷を滅ぼした。そこは、もうペンペン草すら生えない廃墟となっている。対象への《敵意》が4点上昇する。',
  276. '対象はあなたのDNA情報をもとに某国が作り出したものである。GMは対象にあなたのスキルから1つを任意に選んで修得させる。対象への《敵意》が1点上昇する。',
  277. 'あなたはかつて対象の同族を絶滅させた。しかし、奴らは死んではいなかったのだ。対象への《敵意》が1点上昇する。',
  278. 'あなたは幼いころに対象と遭遇したが、一顧だにされず見逃された。対象への《敵意》が1点上昇する。',
  279. '何年も前に死んだ、あなたの親しい人は、ちょうど対象の攻撃手段と同じ方法で殺されている。対象への《敵意》が1点上昇する。',
  280. '対象はなんとなくあなたが嫌いな特徴をそなえている。嫌いなものに関連した特徴を設定すること。対象への《敵意》が1点上昇する。',
  281. 'あなたは過去に対象と戦い、完敗を喫している。対象への《敵意》が1点上昇する。対象との戦闘に勝利した場合、経験点10点を得る。',
  282. '対象はあなたの好きなものを穢したり貶めたことがある。好きなものにちなんだ出来事を設定すること。対象への《敵意》が1点上昇する。',
  283. 'あなたは、対象が同族のなかでも強力な個体であることを知っている。対象への《敵意》が2点上昇する。対象の《HP》と威力を6点ずつ上昇させる。',
  284. '対象はあなたが昔飼っていた生き物や持っていたものが変化したものである。対象への《好意》と《敵意》が1点ずつ上昇する。交渉によって対象との戦闘を終わらせた場合、経験点10点を得る。',
  285. 'かつてあなたは対象と同族であった。対象への《好意》と《敵意》が1点ずつ上昇する。',
  286. ]
  287. ),
  288. "PCT" => DiceTable::Table.new(
  289. "PC因縁表",
  290. "2D6",
  291. [
  292. '対象はあなたが追い求めていた敵だった。なぜ敵なのか設定すること。対象への《敵意》が4点上昇する。対象を殺害すると経験点100点を得る。',
  293. '対象は、あなたがあなたのクラスになるきっかけを作った人物である。1分以内に詳細を設定できれば対象への好きな感情値を2点上昇させてよい。',
  294. '対象と共通の知人がいることが発覚する。好きなものにちなんだ知人を設定すること。対象への《好意》が1点上昇する。',
  295. '対象と同じ場所に住んでいたり、通っていたことが分かる。対象への《好意》が1点上昇する。',
  296. 'あなたは何らかの種類の迷宮屋ランキングで対象に負けている。対象への《敵意》が1点上昇する。終了フェイズで対象に(何でもいいので)負けを認めさせれば、経験点を1点獲得する。',
  297. '対象は、なんとなくあなたの好きな特徴を備えているような気がする。好きなものにちなんだ特徴を1つ設定し、対象のプレイヤーの了解をとること。チャンスは1回だ。OKなら対象への《好意》が1点上昇する。',
  298. '対象は何らかの媒体で、あなたに対して好意的でないコメントを出したことがあるような気がする。コメントの詳細はあなたが決定すること。対象への《敵意》が1点上昇する。',
  299. 'あなたは対象に関する良い噂を聞いたことがある。噂の内容を決定したうえで、対象への《好意》が1点上昇する。',
  300. '対象は実は幼馴染だったことが明らかになる。容姿の変化などで気付かなかったのだ。対象への《好意》が1点上昇する。',
  301. '対象が実は兄弟であったことが明らかになる。家庭の事情を1分で考えだせれば、対象への《好意》が1点上昇する。',
  302. 'あなたと対象は、今まで隠していたが実はつきあっている。対象のプレイヤーの了解を15秒以内にとることができれば、お互いへの愛情の《好意》を4点上昇させることができる。',
  303. ]
  304. ),
  305. "LCT" => DiceTable::Table.new(
  306. "ラブ因縁表",
  307. "2D6",
  308. [
  309. 'あなたは対象と過去にいい友人だった。対象への《好意》が2点上昇するが、その属性は友情に変化する。',
  310. 'あなたは対象を本来とは別の性別だと思い込んで片思いしていた。対象への《敵意》が2点、または《好意》が1点上昇する。',
  311. 'あなたはかつて親友であった対象に恋人を奪われたことがある。対象への《敵意》が1点上昇する。',
  312. '対象は、あなたの好きなものによく似ている。好きなものから1つを選んで、どう似ているか説明できたら、対象への《好意》が1点上昇する。',
  313. '対象をよく見たらけっこう可愛いような気がしてきた。対象への《好意》が1点上昇し、対象への《好意》をすべて愛情に変換する。',
  314. 'あなたは対象と過去につきあっていたことがある。現在はどうだか分からないが、あのころは本気だった。対象への《好意》が1点上昇する。',
  315. '対象は、むかしあなたが好きだった人と印象がよく似ている。対象への《好意》が1点上昇する。',
  316. 'あなたは対象に助けられたり、命を救われたことがある。1分以内に設定を作り上げられれば、対象への《好意》が1点上昇する。',
  317. 'あなたは対象に振られ、失意のあまり自殺しようとしたことがある。対象への《好意》と《敵意》が1点上昇する。',
  318. 'あなたは昔から、対象を独占したいと思っていた。対象があなた以外と関わるたびに怒りを募らせていたのだ。対象への《好意》と《敵意》が2点ずつ上昇する。',
  319. 'なんだか良く分からないが、とにかく好きでたまらない。対象への《好意》が3点上昇し、対象への《好意》をすべて愛情に変換する。'
  320. ]
  321. ),
  322. "MPT" => DiceTable::Table.new(
  323. "相場表",
  324. "2D6",
  325. [
  326. 'なし',
  327. '肉',
  328. '牙',
  329. '鉄',
  330. '魔素',
  331. '機械',
  332. '衣料',
  333. '木',
  334. '火薬',
  335. '情報',
  336. '革',
  337. ]
  338. ),
  339. "T1T" => DiceTable::Table.new(
  340. "お宝1表",
  341. "1D6",
  342. [
  343. '何もなし。',
  344. '何もなし。',
  345. 'そのモンスターの素材欄の中から、好きな素材を1個。',
  346. 'そのモンスターの素材欄の中から、好きな素材を2個。',
  347. 'そのモンスターの素材欄の中から、好きな素材を3個。',
  348. '【お弁当】1個。',
  349. ]
  350. ),
  351. "T2T" => DiceTable::Table.new(
  352. "お宝2表",
  353. "1D6",
  354. [
  355. 'そのモンスターの素材欄の中から、好きな素材を3個。',
  356. 'そのモンスターの素材欄の中から、好きな素材を4個。',
  357. 'そのモンスターの素材欄の中から、好きな素材を5個。',
  358. 'ランダムな回復アイテム1個。',
  359. 'ランダムな武具アイテム1個。そのアイテムにレベルがあれば、レベル1のアイテムとなる。',
  360. 'ランダムなレアアイテム1個。',
  361. ]
  362. ),
  363. "T3T" => DiceTable::Table.new(
  364. "お宝3表",
  365. "1D6",
  366. [
  367. 'そのモンスターの素材欄の中から、好きな素材を5個。',
  368. 'そのモンスターの素材欄の中から、好きな素材を7個。',
  369. 'そのモンスターの素材欄の中から、好きな素材を10個。',
  370. '好きなコモンアイテムのカテゴリ1種を選ぶ。そのカテゴリの中からランダムなアイテム1個。そのアイテムにレベルがあれば、レベル1のアイテムとなる。',
  371. 'ランダムなレアアイテム1個',
  372. 'ランダムなレアアイテム1個。そのアイテムにレベルがあれば、レベル1のアイテムとなる。',
  373. ]
  374. ),
  375. "T4T" => DiceTable::Table.new(
  376. "お宝4表",
  377. "1D6",
  378. [
  379. 'そのモンスターの素材欄の中から、好きな素材を5個。',
  380. 'そのモンスターの素材欄の中から、好きな素材を10個。',
  381. '好きなコモンアイテムのカテゴリ1種を選ぶ。そのカテゴリの中からランダムなアイテム1個。そのアイテムにレベルがあれば、レベル2のアイテムとなる。',
  382. '好きなコモンアイテムのカテゴリ1種を選ぶ。そのカテゴリの中からランダムなアイテム1個。そのアイテムにレベルがあれば、レベル3のアイテムとなる。',
  383. 'ランダムなレアアイテム1個。そのアイテムにレベルがあれば、レベル1のアイテムとなる。',
  384. 'ランダムなレアアイテム1個。そのアイテムにレベルがあれば、レベル2のアイテムとなる。',
  385. ]
  386. ),
  387. }.freeze
  388. 1 register_prefix('\d+MD6?', '\d+R6', TABLES.keys)
  389. end
  390. end
  391. end

lib/bcdice/game_system/MeikyuKingdom.rb

98.86% lines covered

90.0% branches covered

264 relevant lines. 261 lines covered and 3 lines missed.
110 total branches, 99 branches covered and 11 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MeikyuKingdom < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'MeikyuKingdom'
  7. # ゲームシステム名
  8. 1 NAME = '迷宮キングダム'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'めいきゆうきんくたむ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定 (nMK+m)
  14.  n個のD6を振って大きい物二つだけみて達成値を算出します。修正mも可能です。
  15.  絶対成功と絶対失敗も自動判定します。
  16. ・各種表
  17.  ・散策表(〜RT):生活散策表 LRT/治安散策表 ORT/文化散策表 CRT/軍事散策表 ART/お祭り表 FRT
  18.  ・休憩表(〜BT):才覚休憩表 TBT/魅力休憩表 CBT/探索休憩表 SBT/武勇休憩表 VBT/お祭り休憩表 FBT/捜索後休憩表 ABT/全体休憩表 WBT/カップル休憩表 LBT
  19.  ・ハプニング表(〜HT):才覚ハプニング表 THT/魅力ハプニング表 CHT/探索ハプニング表 SHT
  20.   /武勇ハプニング表 VHT
  21.  ・王国災厄表 KDT/王国変動表 KCT/王国変動失敗表 KMT
  22.  ・王国名決定表1/2/3/4/5 KNT1/KNT2/KNT3/KNT4
  23.  ・痛打表 CAT/致命傷表 FWT/戦闘ファンブル表 CFT
  24.  ・道中表 TT/交渉表 NT/感情表 ET/相場表 MPT
  25.  ・お宝表1/2/3/4/5 T1T/T2T/T3T/T4T/T5T
  26.  ・名前表 NAMEx (xは個数)
  27.  ・名前表A NAMEA/名前表B NAMEB/エキゾチック名前表 NAMEEX/ファンタジック名前表 NAMEFA
  28.  ・アイテム関連(猟奇戦役不使用の場合をカッコ書きで出力)
  29.   ・デバイスファクトリー  DFT
  30.   ・アイテムカテゴリ決定表 IDT
  31.   ・アイテム表(〜IT):武具 WIT/生活 LIT/回復 RIT/探索 SIT/レア武具 RWIT/レア一般 RUIT
  32.   ・アイテム特性決定表   IFT
  33.  ・ランダムエンカウント表 nRET (nはレベル,1〜6)
  34.  ・地名決定表    PNTx (xは個数)
  35.  ・迷宮風景表    MLTx (xは個数)
  36.  ・単語表1/2/3/4 WORD1/WORD2/WORD3/WORD4
  37. ・D66ダイスあり
  38. INFO_MESSAGE_TEXT
  39. 1 register_prefix(
  40. '\d+MK', '\d+R6',
  41. 'LRT', 'ORT', 'CRT', 'ART', 'FRT',
  42. 'TBT', 'CBT', 'SBT', 'VBT', 'FBT', 'ABT', 'WBT', 'LBT',
  43. 'THT', 'CHT', 'SHT', 'VHT',
  44. 'KDT', 'KCT', 'KMT',
  45. 'CAT', 'FWT', 'CFT',
  46. 'TT', 'NT', 'ET', 'MPT',
  47. 'T1T', 'T2T', 'T3T', 'T4T', 'T5T',
  48. 'NAME',
  49. 'DFT', 'IDT',
  50. 'WIT', 'LIT', 'RIT', 'SIT', 'RWIT', 'RUIT',
  51. 'IFT',
  52. '\d+RET',
  53. 'PNT', 'MLT',
  54. 'KNT', 'WORD'
  55. )
  56. 1 def initialize(command)
  57. 812 super(command)
  58. 812 @sort_add_dice = true
  59. 812 @d66_sort_type = D66SortType::ASC
  60. end
  61. 1 def replace_text(string)
  62. 630 debug("change_text before string", string)
  63. 630 string = string.gsub(/(\d+)MK6/i) { "#{Regexp.last_match(1)}R6" }
  64. 696 string = string.gsub(/(\d+)MK/i) { "#{Regexp.last_match(1)}R6" }
  65. 630 debug("change_text after string", string)
  66. 630 return string
  67. end
  68. 1 def result_nd6(total, dice_total, dice_list, cmp_op, target)
  69. 33 then: 1 else: 32 return Result.nothing if target == "?"
  70. 32 else: 32 then: 0 return nil unless cmp_op == :>=
  71. 32 result = result_nd6_only(total, dice_total, cmp_op, target)
  72. 32 result.text += kiryoku_result(total, dice_list, target)
  73. 32 return result
  74. end
  75. 1 def result_nd6_only(total, dice_total, cmp_op, target)
  76. 49 else: 49 then: 0 return nil unless cmp_op == :>=
  77. 49 then: 2 if dice_total <= 2
  78. 2 else: 47 Result.fumble("絶対失敗")
  79. 47 then: 11 elsif dice_total >= 12
  80. 11 else: 36 Result.critical("絶対成功")
  81. 36 then: 24 elsif total >= target
  82. 24 Result.success("成功")
  83. else: 12 else
  84. 12 Result.failure("失敗")
  85. end
  86. end
  87. 1 def result_2d6_text(total, dice_total, cmp_op, target)
  88. 17 then: 17 else: 0 text = result_nd6_only(total, dice_total, cmp_op, target)&.text
  89. 17 then: 0 else: 17 return "" if text.nil?
  90. 17 return " > #{text}"
  91. end
  92. 1 def kiryoku_result(total_n, dice_list, diff)
  93. 31 num_6 = dice_list.count(6)
  94. 31 then: 12 if num_6 == 0
  95. 12 else: 19 return ""
  96. 19 then: 6 else: 13 elsif num_6 >= 2
  97. 6 return " & 《気力》#{num_6}点獲得"
  98. end
  99. 41 none6_list = dice_list.reject { |i| i == 6 }.sort
  100. 13 maxDice1 = none6_list.pop.to_i
  101. 13 maxDice2 = none6_list.pop.to_i
  102. 13 debug("maxDice1", maxDice1)
  103. 13 debug("maxDice2", maxDice2)
  104. 13 debug("total_n", total_n)
  105. 13 none6Total_n = total_n - 6 + maxDice2
  106. 13 debug("none6Total_n", none6Total_n)
  107. 13 none6Dice_n = maxDice1 + maxDice2
  108. 13 debug("none6Dice_n", none6Dice_n)
  109. 13 debug("diff", diff)
  110. 13 then: 1 else: 12 none6DiceReuslt = (none6Total_n >= diff ? " > 成功" : " > 失敗")
  111. 13 return " (もしくは) #{none6Total_n}#{none6DiceReuslt} & 《気力》1点獲得"
  112. end
  113. 1 def mayokin_check(string)
  114. 630 debug("mayokin_check string", string)
  115. 630 string = replace_text(string)
  116. 630 m = /^S?((\d+)R6([+\-\d]*)(([>=]+)(\d+))?)/i.match(string)
  117. 630 else: 66 then: 564 unless m
  118. 564 return nil
  119. end
  120. 66 string = m[1]
  121. 66 diceCount = m[2].to_i
  122. 66 modifyText = m[3]
  123. 66 signOfInequality = m[5] || ""
  124. 66 diff = m[6].to_i
  125. 66 then: 66 else: 0 bonus = modifyText ? ArithmeticEvaluator.eval(modifyText) : 0
  126. 66 dice_list = @randomizer.roll_barabara(diceCount, 6).sort
  127. 66 dice_str = dice_list.join(",")
  128. 66 then: 57 else: 9 dice1 = diceCount >= 2 ? dice_list[diceCount - 2] : 0
  129. 66 then: 66 else: 0 dice2 = diceCount >= 1 ? dice_list[diceCount - 1] : 0
  130. 66 dice_now = dice1 + dice2
  131. 66 debug("dice1, dice2, dice_now", dice1, dice2, dice_now)
  132. 66 total_n = dice_now + bonus
  133. 66 dice_str = "[#{dice_str}]"
  134. 66 output = "#{dice_now}#{dice_str}"
  135. 66 then: 38 if bonus > 0
  136. 38 else: 28 output += "+#{bonus}"
  137. 28 then: 0 else: 28 elsif bonus < 0
  138. output += bonus.to_s
  139. end
  140. 66 then: 60 if output =~ /[^\d\[\]]+/
  141. 60 output = "(#{string}) > #{output} > #{total_n}"
  142. else: 6 else
  143. 6 output = "(#{string}) > #{total_n}"
  144. end
  145. 66 then: 17 else: 49 if signOfInequality != "" # 成功度判定処理
  146. 17 cmp_op = Normalize.comparison_operator(signOfInequality)
  147. 17 output += result_2d6_text(total_n, dice_now, cmp_op, diff)
  148. 17 output += kiryoku_result(total_n, dice_list, diff)
  149. end
  150. 66 return output
  151. end
  152. 1 def eval_game_system_specific_command(command)
  153. 630 output = ""
  154. 630 type = ""
  155. 630 total_n = ""
  156. 630 then: 66 else: 564 if (result = mayokin_check(command))
  157. 66 return result
  158. end
  159. 564 case command
  160. when: 2 when /^NAMEA/i
  161. 2 debug("namea passed")
  162. 2 type = '名前A'
  163. 2 total_n = @randomizer.roll_d66(D66SortType::ASC)
  164. 2 output = mk_name_a_table(total_n)
  165. when: 2 when /^NAMEB/i
  166. 2 type = '名前B'
  167. 2 total_n = @randomizer.roll_d66(D66SortType::ASC)
  168. 2 output = mk_name_b_table(total_n)
  169. when: 2 when /^NAMEEX/i
  170. 2 type = 'エキゾチック名前'
  171. 2 total_n = @randomizer.roll_d66(D66SortType::ASC)
  172. 2 output = mk_name_ex_table(total_n)
  173. when: 2 when /^NAMEFA/i
  174. 2 type = 'ファンタジック名前'
  175. 2 total_n = @randomizer.roll_d66(D66SortType::ASC)
  176. 2 output = mk_name_fa_table(total_n)
  177. when: 31 when /^NAME(\d*)/i
  178. 31 type = '名前'
  179. 31 count = getCount(Regexp.last_match(1))
  180. 31 names = ""
  181. 31 count.times do |_i|
  182. 131 name, dice = mk_name_table
  183. 131 names += "[#{dice}]#{name} "
  184. end
  185. 31 output = names.strip
  186. 31 total_n = count
  187. when: 33 when /^PNT(\d*)/i
  188. 33 type = '地名'
  189. 33 count = getCount(Regexp.last_match(1))
  190. 33 output = mk_pn_decide_table(count)
  191. 33 total_n = count
  192. when: 33 when /^MLT(\d*)/i
  193. 33 type = '地名'
  194. 33 count = getCount(Regexp.last_match(1))
  195. 33 output = mk_ls_decide_table(count)
  196. 33 total_n = count
  197. when: 10 when /^DFT/i
  198. 10 type = 'デバイスファクトリー'
  199. 10 output = mk_device_factory_table()
  200. 10 total_n = 1
  201. when: 10 when /^LRT/i
  202. 10 type = '生活散策'
  203. 10 output, total_n = mk_life_research_table
  204. when: 10 when /^ORT/i
  205. 10 type = '治安散策'
  206. 10 output, total_n = mk_order_research_table
  207. when: 10 when /^CRT/i
  208. 10 type = '文化散策'
  209. 10 output, total_n = mk_calture_research_table
  210. when: 10 when /^ART/i
  211. 10 type = '軍事散策'
  212. 10 output, total_n = mk_army_research_table
  213. when: 10 when /^FRT/i
  214. 10 type = 'お祭り'
  215. 10 output, total_n = mk_festival_table
  216. # 休憩表(2D6)
  217. when: 10 when /^TBT/i
  218. 10 type = '才覚休憩'
  219. 10 output, total_n = mk_talent_break_table
  220. when: 10 when /^CBT/i
  221. 10 type = '魅力休憩'
  222. 10 output, total_n = mk_charm_break_table
  223. when: 10 when /^SBT/i
  224. 10 type = '探索休憩'
  225. 10 output, total_n = mk_search_break_table
  226. when: 10 when /^VBT/i
  227. 10 type = '武勇休憩'
  228. 10 output, total_n = mk_valor_break_table
  229. when: 10 when /^FBT/i
  230. 10 type = 'お祭り休憩'
  231. 10 output, total_n = mk_festival_break_table
  232. # ハプニング表(2D6)
  233. when: 10 when /^THT/i
  234. 10 type = '才覚ハプニング'
  235. 10 output, total_n = mk_talent_happening_table
  236. when: 10 when /^CHT/i
  237. 10 type = '魅力ハプニング'
  238. 10 output, total_n = mk_charm_happening_table
  239. when: 10 when /^SHT/i
  240. 10 type = '探索ハプニング'
  241. 10 output, total_n = mk_search_happening_table
  242. when: 10 when /^VHT/i
  243. 10 type = '武勇ハプニング'
  244. 10 output, total_n = mk_valor_happening_table
  245. # お宝表
  246. when: 11 when /^MPT/i
  247. 11 type = '相場'
  248. 11 output, total_n = mk_market_price_table
  249. when: 10 when /^T1T/i
  250. 10 type = 'お宝1'
  251. 10 output, total_n = mk_treasure1_table
  252. when: 10 when /^T2T/i
  253. 10 type = 'お宝2'
  254. 10 output, total_n = mk_treasure2_table
  255. when: 10 when /^T3T/i
  256. 10 type = 'お宝3'
  257. 10 output, total_n = mk_treasure3_table
  258. when: 10 when /^T4T/i
  259. 10 type = 'お宝4'
  260. 10 output, total_n = mk_treasure4_table
  261. when: 10 when /^T5T/i
  262. 10 type = 'お宝5'
  263. 10 output, total_n = mk_treasure5_table
  264. # アイテム表
  265. when: 10 when /^RWIT/i
  266. 10 type = 'レア武具アイテム'
  267. 10 total_n = @randomizer.roll_d66(D66SortType::NO_SORT)
  268. 10 output = mk_rare_weapon_item_table(total_n)
  269. when: 10 when /^RUIT/i
  270. 10 type = 'レア一般アイテム'
  271. 10 total_n = @randomizer.roll_d66(D66SortType::NO_SORT)
  272. 10 output = mk_rare_item_table(total_n)
  273. when: 10 when /^WIT/i
  274. 10 type = '武具アイテム'
  275. 10 total_n = @randomizer.roll_d66(D66SortType::ASC)
  276. 10 output = mk_weapon_item_table(total_n)
  277. when: 10 when /^LIT/i
  278. 10 type = '生活アイテム'
  279. 10 total_n = @randomizer.roll_d66(D66SortType::ASC)
  280. 10 output = mk_life_item_table(total_n)
  281. when: 10 when /^RIT/i
  282. 10 type = '回復アイテム'
  283. 10 total_n = @randomizer.roll_d66(D66SortType::ASC)
  284. 10 output = mk_rest_item_table(total_n)
  285. when: 10 when /^SIT/i
  286. 10 type = '探索アイテム'
  287. 10 total_n = @randomizer.roll_d66(D66SortType::ASC)
  288. 10 output = mk_search_item_table(total_n)
  289. when: 10 when /^IFT/i
  290. 10 type = 'アイテム特性'
  291. 10 total_n = @randomizer.roll_sum(2, 6)
  292. 10 output = mk_item_features_table(total_n)
  293. when: 10 when /^IDT/i
  294. 10 type = 'アイテムカテゴリ決定'
  295. 10 total_n = @randomizer.roll_once(6)
  296. 10 output = mk_item_decide_table(total_n)
  297. # ランダムエンカウント表
  298. when: 10 when /^1RET/i
  299. 10 type = '1Lvランダムエンカウント'
  300. 10 total_n = @randomizer.roll_once(6)
  301. 10 output = mk_random_encount1_table(total_n)
  302. when: 10 when /^2RET/i
  303. 10 type = '2Lvランダムエンカウント'
  304. 10 total_n = @randomizer.roll_once(6)
  305. 10 output = mk_random_encount2_table(total_n)
  306. when: 10 when /^3RET/i
  307. 10 type = '3Lvランダムエンカウント'
  308. 10 total_n = @randomizer.roll_once(6)
  309. 10 output = mk_random_encount3_table(total_n)
  310. when: 10 when /^4RET/i
  311. 10 type = '4Lvランダムエンカウント'
  312. 10 total_n = @randomizer.roll_once(6)
  313. 10 output = mk_random_encount4_table(total_n)
  314. when: 10 when /^5RET/i
  315. 10 type = '5Lvランダムエンカウント'
  316. 10 total_n = @randomizer.roll_once(6)
  317. 10 output = mk_random_encount5_table(total_n)
  318. when: 10 when /^6RET/i
  319. 10 type = '6Lvランダムエンカウント'
  320. 10 total_n = @randomizer.roll_once(6)
  321. 10 output = mk_random_encount6_table(total_n)
  322. # その他表
  323. when: 10 when /^KDT/i
  324. 10 type = '王国災厄'
  325. 10 output, total_n = mk_kingdom_disaster_table
  326. when: 10 when /^KCT/i
  327. 10 type = '王国変動'
  328. 10 output, total_n = mk_kingdom_change_table
  329. when: 10 when /^KMT/i
  330. 10 type = '王国変動失敗'
  331. 10 output, total_n = mk_kingdom_mischange_table
  332. when: 10 when /^CAT/i
  333. 10 type = '痛打'
  334. 10 output, total_n = mk_critical_attack_table
  335. when: 10 when /^FWT/i
  336. 10 type = '致命傷'
  337. 10 output, total_n = mk_fatal_wounds_table
  338. when: 10 when /^CFT/i
  339. 10 type = '戦闘ファンブル'
  340. 10 output, total_n = mk_combat_fumble_table
  341. when: 10 when /^TT/i
  342. 10 type = '道中'
  343. 10 output, total_n = mk_travel_table
  344. when: 10 when /^NT/i
  345. 10 type = '交渉'
  346. 10 output, total_n = mk_negotiation_table
  347. when: 10 when /^ET/i
  348. 10 type = '感情'
  349. 10 output, total_n = mk_emotion_table
  350. when: 4 when /^KNT(\d+)/i
  351. 4 type = '王国名'
  352. 4 count = getCount(Regexp.last_match(1))
  353. 4 total_n = @randomizer.roll_d66(D66SortType::ASC)
  354. 4 else: 0 case count
  355. when: 2 when 1
  356. 2 output = mk_kingdom_name_1_table(total_n)
  357. when: 1 when 2
  358. 1 output = mk_kingdom_name_2_table(total_n)
  359. when: 1 when 3
  360. 1 output = mk_kingdom_name_3_table(total_n)
  361. end
  362. when: 8 when /^WORD(\d+)/i
  363. 8 type = '単語'
  364. 8 count = getCount(Regexp.last_match(1))
  365. 8 total_n = @randomizer.roll_d66(D66SortType::ASC)
  366. 8 else: 0 case count
  367. when: 2 when 1
  368. 2 output = mk_word_1_table(total_n)
  369. when: 2 when 2
  370. 2 output = mk_word_2_table(total_n)
  371. when: 2 when 3
  372. 2 output = mk_word_3_table(total_n)
  373. when: 2 when 4
  374. 2 output = mk_word_4_table(total_n)
  375. end
  376. when: 2 when /^ABT/i
  377. 2 type = '捜索後休憩'
  378. 2 output, total_n = getAftersearchBreakTable()
  379. when: 2 when /^WBT/i
  380. 2 type = '全体休憩'
  381. 2 output, total_n = getWholeBreakTable()
  382. when: 2 when /^LBT/i
  383. 2 type = 'カップル休憩'
  384. 2 output, total_n = getLoversBreakTable()
  385. else: 0 else
  386. return nil
  387. end
  388. 564 then: 564 if output != '1'
  389. 564 return "#{type}表(#{total_n}) > #{output}"
  390. else: 0 else
  391. return nil
  392. end
  393. end
  394. 1 def getCount(countText)
  395. 114 then: 34 else: 80 if countText.empty?
  396. 34 return 1
  397. end
  398. 80 return countText.to_i
  399. end
  400. end
  401. end
  402. end
  403. 1 require 'bcdice/game_system/meikyu_kingdom/item_table'
  404. 1 require 'bcdice/game_system/meikyu_kingdom/kingdom_name_table'
  405. 1 require 'bcdice/game_system/meikyu_kingdom/landscape_table'
  406. 1 require 'bcdice/game_system/meikyu_kingdom/name_tables'
  407. 1 require 'bcdice/game_system/meikyu_kingdom/placename_table'
  408. 1 require 'bcdice/game_system/meikyu_kingdom/word_table'
  409. 1 require 'bcdice/game_system/meikyu_kingdom/tables'

lib/bcdice/game_system/MeikyuKingdomBasic.rb

67.88% lines covered

57.78% branches covered

137 relevant lines. 93 lines covered and 44 lines missed.
45 total branches, 26 branches covered and 19 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/MeikyuKingdom"
  3. 1 require "bcdice/dice_table/table"
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class MeikyuKingdomBasic < MeikyuKingdom
  7. # ゲームシステムの識別子
  8. 1 ID = 'MeikyuKingdomBasic'
  9. # ゲームシステム名
  10. 1 NAME = '迷宮キングダム 基本ルールブック'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = 'めいきゆうきんくたむきほんるうるふつく'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  15. ・判定 (nMK+m)
  16.  n個のD6を振って大きい物二つだけみて達成値を算出します。修正mも可能です。
  17.  絶対成功と絶対失敗も自動判定します。
  18. ・各種表
  19.  ・休憩表:才覚 TBT/魅力 CBT/探索 SBT/武勇 VBT
  20. お祭り FBT/空振り EBT/全体 WBT/カップル LBT
  21.  ・ハプニング表:才覚 THT/魅力 CHT/探索 SHT/武勇 VHT
  22.  ・視察表 RT/情報収集表 IG/ランダムマップ選択表 RMS
  23.  ・痛打表 CAT/致命傷表 FWT/戦闘ファンブル表 CFT
  24.  ・道中表 TT/交渉表 NT/相場表 MPT/王国災厄表 KDT/王国変動表 KCT
  25.  ・感情表 ET/好意表 FET/敵意表 HET
  26.  ・お宝表1/2/3/4/5 T1T/T2T/T3T/T4T/T5T
  27.  ・特殊遭遇表 SE
  28.    上級:人工 ARN/水域 WEN/自然 NEN/洞窟 CEN/天空 SEN/異界 OEN
  29. ・潜在能力:スキル決定表 SDT
  30.   基本:肉弾 BUS/射撃 SHS/星術 ASS/召喚 SUS/科学 SCS
  31.      迷宮 LAS/交渉 NES/便利 COS/芸能 ENS/道具 TOS
  32.   上級:肉弾 ABUS/射撃 ASHS/星術 AASS/召喚 ASUS/科学 ASCS
  33.      迷宮 ALAS/交渉 ANES/便利 ACOS/芸能 AENS/道具 ATOS
  34. ・アイテム関連(上級不使用の場合、カッコ書きのものを使用して下さい)
  35.  ・コモンアイテムランダム決定表 CIR
  36.    コモンアイテム表:武具 WIT/生活 LIT/回復 RIT/探索 SIT
  37.  ・レア武具アイテムランダム決定表 RWIR/レア一般アイテムランダム決定表 RUIR(上級込)
  38.    レアアイテム表:基本武具 NRWT/基本一般 NRUT/上級武具 ARWT/上級一般 ARUT
  39.  ・デヴァイスファクトリー DFTx (xは特性の個数)
  40. ・王国人物作成関連
  41.  ・王国名決定表1/2/3 KNT1/KNT2/KNT3
  42.  ・王国環境表 KET:技術 TET/国風 NST/資源 RET/人材 HRT/施設 FAT/血族 BLT
  43.  ・名前表 NAMEx (xは個数)
  44.    名前A NAMEA/名前B NAMEB/エキゾチック NAMEEX/ファンタジック NAMEFA
  45.  ・新名前表 NNAMEx (xは個数)
  46.    芸術 NMAR/食べ物 NMFO/日用品 NMDN/地名 NMPL/機械 NMMA/神様 NMGO
  47.  ・単語表1/2/3/4 WORD1/WORD2/WORD3/WORD4
  48.  ・生まれ決定表 BDT/生まれ表:才覚 TBO/魅力 CBO/探索 SBO/武勇 VBO
  49.  ・初期装備表 IEQ
  50.  ・地名決定表 PNTx (xは個数)/迷宮風景表 MLTx (xは個数)
  51. ・D66ダイスあり
  52. INFO_MESSAGE_TEXT
  53. 1 register_prefix(
  54. '\d+MK', '\d+R6',
  55. 'IG', 'TT', 'NT', 'RMS',
  56. 'CFT', 'FWT', 'CAT', 'KDT', 'KCT',
  57. 'TBT', 'CBT', 'SBT', 'VBT', 'FBT', 'EBT', 'WBT', 'LBT',
  58. 'THT', 'CHT', 'SHT', 'VHT',
  59. 'BDT', 'TBO', 'CBO', 'SBO', 'VBO',
  60. 'ET', 'FET', 'HET', 'SDT', 'IEQ', 'FRT',
  61. 'T1T', 'T2T', 'T3T', 'T4T', 'T5T',
  62. 'MPT', 'KNT', 'WORD', 'NAME', 'NNAME', 'NM',
  63. 'RT', 'CIR', 'RUIR', 'RWIR',
  64. 'WIT', 'LIT', 'RIT', 'SIT', 'NRWT', 'NRUT', 'ARWT', 'ARUT',
  65. 'KET', 'TET', 'NST', 'RET', 'FAT', 'HRT', 'BLT',
  66. 'BUS', 'SHS', 'ASS', 'SUS', 'SCS', 'LAS', 'NES', 'COS', 'ENS', 'TOS',
  67. 'ABUS', 'ASHS', 'AASS', 'ASUS', 'ASCS', 'ALAS', 'ANES', 'ACOS', 'AENS', 'ATOS',
  68. 'SE', 'ARN', 'WEN', 'NEN', 'CEN', 'SEN', 'OEN',
  69. 'DFT',
  70. 'PNT', 'MLT'
  71. )
  72. 1 def initialize(command)
  73. 190 super(command)
  74. 190 @sort_add_dice = true
  75. 190 @d66_sort_type = D66SortType::ASC
  76. end
  77. 1 def kiryoku_result(_total_n, dice_list, _diff)
  78. 18 num_6 = dice_list.count(6)
  79. 18 then: 7 if num_6 == 0
  80. 7 ""
  81. else: 11 else
  82. 11 " & 《気力》#{num_6}点獲得"
  83. end
  84. end
  85. 1 def eval_game_system_specific_command(command)
  86. 178 output = ""
  87. 178 type = ""
  88. 178 total_n = ""
  89. 178 then: 126 if (output = roll_tables(command, TABLES))
  90. 126 return output
  91. else
  92. else: 52
  93. 52 else: 29 case command
  94. when: 4 when /^DFT(\d*)$/i
  95. 4 feature_count = Regexp.last_match(1).to_i
  96. 4 return roll_device_factory_table(feature_count)
  97. when: 0 when /^NRWT/i
  98. type = '基本レア武具アイテム'
  99. total_n = @randomizer.roll_d66(D66SortType::NO_SORT)
  100. output = mk_normal_rare_weapon_item_table(total_n)
  101. when: 0 when /^NRUT/i
  102. type = '基本レア一般アイテム'
  103. total_n = @randomizer.roll_d66(D66SortType::NO_SORT)
  104. output = mk_normal_rare_item_table(total_n)
  105. when: 0 when /^ARWT/i
  106. type = '上級レア武具アイテム'
  107. total_n = @randomizer.roll_d66(D66SortType::NO_SORT)
  108. output = mk_advanced_rare_weapon_item_table(total_n)
  109. when: 0 when /^ARUT/i
  110. type = '上級レア一般アイテム'
  111. total_n = @randomizer.roll_d66(D66SortType::NO_SORT)
  112. output = mk_advanced_rare_item_table(total_n)
  113. when: 0 when /^CIR/i
  114. type = 'コモンアイテムランダム決定'
  115. total_n = @randomizer.roll_once(4)
  116. output = mk_common_item_random_table(total_n)
  117. when: 0 when /^RWIR/i
  118. type = 'レア武具アイテムランダム決定'
  119. total_n = @randomizer.roll_once(6)
  120. output = mk_rare_weapon_item_random_table(total_n)
  121. when: 0 when /^RUIR/i
  122. type = 'レア一般アイテムランダム決定'
  123. total_n = @randomizer.roll_once(6)
  124. output = mk_rare_usual_item_random_table(total_n)
  125. when: 1 when /^NMAR/i
  126. 1 debug("namea passed")
  127. 1 type = '芸術系名前'
  128. 1 total_n = @randomizer.roll_d66(D66SortType::ASC)
  129. 1 output = mk_name_ar_table(total_n)
  130. when: 1 when /^NMFO/i
  131. 1 type = '食べ物系名前'
  132. 1 total_n = @randomizer.roll_d66(D66SortType::ASC)
  133. 1 output = mk_name_fo_table(total_n)
  134. when: 1 when /^NMDN/i
  135. 1 type = '日用品系名前'
  136. 1 total_n = @randomizer.roll_d66(D66SortType::ASC)
  137. 1 output = mk_name_dn_table(total_n)
  138. when: 1 when /^NMPL/i
  139. 1 type = '地名系名前'
  140. 1 total_n = @randomizer.roll_d66(D66SortType::ASC)
  141. 1 output = mk_name_pl_table(total_n)
  142. when: 1 when /^NMMA/i
  143. 1 type = '機械系名前'
  144. 1 total_n = @randomizer.roll_d66(D66SortType::ASC)
  145. 1 output = mk_name_ma_table(total_n)
  146. when: 1 when /^NMGO/i
  147. 1 type = '神様系名前'
  148. 1 total_n = @randomizer.roll_d66(D66SortType::ASC)
  149. 1 output = mk_name_go_table(total_n)
  150. when: 2 when /^NNAME(\d*)/i
  151. 2 type = '新名前'
  152. 2 count = getCount(Regexp.last_match(1))
  153. 2 names = ""
  154. 2 count.times do |_i|
  155. 3 name, dice = mk_new_name_table
  156. 3 names += "[#{dice}]#{name} "
  157. 3 output = names
  158. 3 total_n = count
  159. end
  160. 2 output = output.strip
  161. when: 0 when /^RMS/i
  162. type = 'ランダムマップ選択'
  163. total_n = @randomizer.roll_d66(D66SortType::NO_SORT)
  164. output = mk_random_map_select_table(total_n)
  165. when: 3 when /^KNT(\d+)/i
  166. 3 type = '王国名決定'
  167. 3 count = getCount(Regexp.last_match(1))
  168. 3 total_n = @randomizer.roll_d66(D66SortType::ASC)
  169. 3 else: 0 case count
  170. when: 1 when 1
  171. 1 output = mk_kingdom_name_1_table(total_n)
  172. when: 1 when 2
  173. 1 output = mk_kingdom_name_2_table(total_n)
  174. when: 1 when 3
  175. 1 output = mk_kingdom_name_3_table(total_n)
  176. end
  177. when: 2 when /^KET/i
  178. 2 type = '王国環境'
  179. 2 total_n = @randomizer.roll_once(6)
  180. 2 output = mk_kingdom_environment_table(total_n)
  181. when: 1 when /^TET/i
  182. 1 type = '技術決定'
  183. 1 total_n = @randomizer.roll_once(6)
  184. 1 output = mk_technic_decide_table(total_n)
  185. when: 1 when /^NST/i
  186. 1 type = '国風決定'
  187. 1 total_n = @randomizer.roll_once(6)
  188. 1 output = mk_national_style_decide_table(total_n)
  189. when: 1 when /^RET/i
  190. 1 type = '資源決定'
  191. 1 total_n = @randomizer.roll_once(6)
  192. 1 output = mk_resource_decide_table(total_n)
  193. when: 1 when /^FAT/i
  194. 1 type = '施設決定'
  195. 1 total_n = @randomizer.roll_once(6)
  196. 1 output = mk_facility_decide_table(total_n)
  197. when: 1 when /^HRT/i
  198. 1 type = '人材決定'
  199. 1 total_n = @randomizer.roll_once(6)
  200. 1 output = mk_human_resources_decide_table(total_n)
  201. when: 1 when /^BLT/i
  202. 1 type = '血族決定'
  203. 1 total_n = @randomizer.roll_once(6)
  204. 1 output = mk_blood_decide_table(total_n)
  205. when: 0 when /^ABUS/i
  206. type = '上級肉弾スキル'
  207. output, total_n = mk_advanced_bullet_skill_table
  208. when: 0 when /^ASHS/i
  209. type = '上級射撃スキル'
  210. output, total_n = mk_advanced_shooting_skill_table
  211. when: 0 when /^AASS/i
  212. type = '上級星術スキル'
  213. output, total_n = mk_advanced_astrology_skill_table
  214. when: 0 when /^ASUS/i
  215. type = '上級召喚スキル'
  216. output, total_n = mk_advanced_summon_skill_table
  217. when: 0 when /^ASCS/i
  218. type = '上級科学スキル'
  219. output, total_n = mk_advanced_science_skill_table
  220. when: 0 when /^ALAS/i
  221. type = '上級迷宮スキル'
  222. output, total_n = mk_advanced_labyrinth_skill_table
  223. when: 0 when /^ANES/i
  224. type = '上級交渉スキル'
  225. output, total_n = mk_advanced_negotiation_skill_table
  226. when: 0 when /^ACOS/i
  227. type = '上級便利スキル'
  228. output, total_n = mk_advanced_convenient_skill_table
  229. when: 0 when /^AENS/i
  230. type = '上級芸能スキル'
  231. output, total_n = mk_advanced_entertainment_skill_table
  232. when: 0 when /^ATOS/i
  233. type = '上級道具スキル'
  234. output, total_n = mk_advanced_tool_skill_table
  235. end
  236. 48 then: 19 if !output.nil?
  237. 19 debug("output", output)
  238. 19 output = "#{type}表(#{total_n}) > #{output}"
  239. else: 29 else
  240. 29 super(command)
  241. end
  242. end
  243. end
  244. end
  245. end
  246. end
  247. 1 require "bcdice/game_system/meikyu_kingdom_basic/item_table"
  248. 1 require "bcdice/game_system/meikyu_kingdom_basic/kingdom_table"
  249. 1 require "bcdice/game_system/meikyu_kingdom_basic/name_table"
  250. 1 require "bcdice/game_system/meikyu_kingdom_basic/word_table"
  251. 1 require "bcdice/game_system/meikyu_kingdom_basic/table"

lib/bcdice/game_system/MetalHead.rb

98.81% lines covered

94.59% branches covered

84 relevant lines. 83 lines covered and 1 lines missed.
37 total branches, 35 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/arithmetic_evaluator'
  3. 1 require 'bcdice/dice_table/range_table'
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class MetalHead < Base
  7. # ゲームシステムの識別子
  8. 1 ID = 'MetalHead'
  9. # ゲームシステム名
  10. 1 NAME = 'メタルヘッド'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = 'めたるへつと'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = <<~MESSAGETEXT
  15. ・アビリティロール AR>=目標値
  16. ・スキルロール SR<=目標値(%)
  17. ・命中判定ロール HR<=目標値(%)
  18. 例)AR>=5
  19. 例)SR<=(40+25)
  20. 例)HR<=(50-10)
  21. これらのロールで成否、絶対成功/絶対失敗、クリティカル/アクシデントを自動判定します。
  22. ・クリティカルチャート CC
  23. ・アクシデントチャート 射撃・投擲用:ACL 格闘用:ACS
  24. ・戦闘結果チャート CRCsn s=耐久レベル(SUV) n=数値
  25. 例)CRCA61 SUV=Aを対象とした数値61(62に変換される)の戦闘結果を参照する。
  26. 例)CRCM98 対物で数値98の戦闘結果を参照する。
  27. MESSAGETEXT
  28. 1 register_prefix('AR', 'SR', 'HR<=', 'CC', 'ACT', 'ACL', 'ACS', 'CRC[A-Z]')
  29. 1 def eval_game_system_specific_command(command)
  30. 26 result = roll_tables(command, TABLES)
  31. 26 then: 9 else: 17 return result if result
  32. 17 else: 0 case command
  33. when: 8 when /\ACRC(\w)(\d+)\z/
  34. 8 suv = Regexp.last_match(1)
  35. 8 num = Regexp.last_match(2)
  36. 8 return mh_crc_table(suv, num)
  37. when: 9 when /\AHR<=(.+)/
  38. 9 target = ArithmeticEvaluator.eval(
  39. Regexp.last_match(1), round_type: @round_type
  40. )
  41. 9 return rollHit(target)
  42. end
  43. return nil
  44. end
  45. 1 def change_text(string)
  46. 62 string = string.gsub(/^(S)?AR/i) { "#{Regexp.last_match(1)}2D6" }
  47. 62 string = string.gsub(/^(S)?SR/i) { "#{Regexp.last_match(1)}1D100" }
  48. 58 return string
  49. end
  50. 1 def result_2d6(_total, dice_total, _dice_list, cmp_op, _target)
  51. 7 then: 0 else: 7 return nil if cmp_op != :>=
  52. 7 then: 2 if dice_total >= 12
  53. 2 else: 5 Result.critical("絶対成功")
  54. 5 then: 2 else: 3 elsif dice_total <= 2
  55. 2 Result.fumble("絶対失敗")
  56. end
  57. end
  58. 1 def rollHit(target)
  59. 9 total = @randomizer.roll_once(100)
  60. 9 resultText = getHitResult(total, total, target)
  61. 9 text = "(1D100<=#{target}) > #{total}#{resultText}"
  62. 9 return text
  63. end
  64. 1 def result_1d100(_total, dice_total, cmp_op, _target)
  65. 9 else: 8 then: 1 return nil unless cmp_op == :<=
  66. 8 then: 3 if dice_total <= 5
  67. 3 else: 5 Result.critical("絶対成功")
  68. 5 then: 2 else: 3 elsif dice_total >= 96
  69. 2 Result.fumble("絶対失敗")
  70. end
  71. end
  72. 1 def getHitResult(total_n, _dice_n, diff)
  73. 9 diceValue = total_n % 100
  74. 9 dice1 = diceValue % 10 # 1の位を代入
  75. 9 debug("total_n", total_n)
  76. 9 then: 3 else: 6 return ' > 失敗' if total_n > diff
  77. 6 then: 2 else: 4 return ' > 成功(クリティカル)' if dice1 == 1
  78. 4 then: 1 else: 3 return ' > 失敗(アクシデント)' if dice1 == 0
  79. 3 return ' > 成功'
  80. end
  81. # 戦闘結果チャートを振る
  82. # @param [String] suv 耐久レベル
  83. # @param [String] num 数値
  84. # @return [String] 振った結果
  85. 1 def mh_crc_table(suv, num)
  86. 8 header_parts = ['戦闘結果チャート', num]
  87. 8 separator = ' > '
  88. 8 suv = suv.to_s.upcase
  89. 8 numbuf = num.to_i
  90. 8 then: 1 else: 7 if numbuf < 1
  91. 1 return (header_parts + ['数値が不正です']).join(separator)
  92. end
  93. 7 num_d1 = numbuf % 10
  94. 7 debug("num_d1[#{num_d1}]")
  95. 7 then: 1 else: 6 if num_d1 == 1
  96. 1 numbuf += 1
  97. end
  98. 7 then: 3 else: 4 if num_d1 == 0
  99. 3 numbuf -= 1
  100. end
  101. 7 num_d1 = numbuf % 10
  102. 7 debug("num_d1[#{num_d1}]")
  103. 7 table_point = [
  104. nil, # 0
  105. nil, # 1
  106. "腕部", # 2
  107. "腕部", # 3
  108. "脚部", # 4
  109. "脚部", # 5
  110. "胴部", # 6
  111. "胴部", # 7
  112. "胴部", # 8
  113. "頭部", # 9
  114. ]
  115. table_damage = {
  116. 7 'S' => [{'N' => 2}, {'LW' => 16}, {'MD' => 46}, {'MW' => 56}, {'HD' => 76}, {'HW' => 96}, {'MO' => 106}, {'K' => 116}],
  117. 'A' => [{'LW' => 2}, {'MW' => 46}, {'HW' => 76}, {'MO' => 96}, {'K' => 116}],
  118. 'B' => [{'LW' => 2}, {'MW' => 36}, {'HW' => 66}, {'MO' => 96}, {'K' => 106}],
  119. 'C' => [{'LW' => 2}, {'MW' => 26}, {'HW' => 66}, {'MO' => 86}, {'K' => 106}],
  120. 'D' => [{'LW' => 2}, {'MW' => 26}, {'HW' => 46}, {'MO' => 76}, {'K' => 96}],
  121. 'E' => [{'LW' => 2}, {'MW' => 26}, {'HW' => 39}, {'MO' => 54}, {'K' => 76}],
  122. 'F' => [{'LW' => 2}, {'MW' => 16}, {'HW' => 39}, {'MO' => 54}, {'K' => 66}],
  123. 'G' => [{'LW' => 2}, {'MW' => 6}, {'HW' => 16}, {'MO' => 26}, {'K' => 39}],
  124. 'M' => [{'0' => 2}, {'1' => 22}, {'2' => 42}, {'3' => 62}, {'4' => 82}, {'5' => 92}, {'6' => 102}, {'8' => 112}],
  125. }
  126. 7 then: 1 else: 6 if table_damage[suv].nil?
  127. 1 return (header_parts + [
  128. "耐久レベル(SUV)[#{suv}]",
  129. "耐久レベル(SUV)の値が不正です",
  130. ]).join(separator)
  131. end
  132. 6 damage_level = ''
  133. 6 table_damage[suv].each do |v|
  134. 36 v.each do |d, n|
  135. 36 debug("suv[#{suv}] #{v} #{d} #{n}")
  136. 36 then: 20 else: 16 if n <= numbuf
  137. 20 damage_level = d
  138. end
  139. end
  140. end
  141. 6 result_parts = []
  142. 6 then: 3 else: 3 if numbuf != num.to_i
  143. 3 result_parts.push(numbuf.to_s)
  144. end
  145. 6 then: 1 if suv == 'M'
  146. 1 result_parts.push('耐物', "HP[#{damage_level}]")
  147. else: 5 else
  148. 5 result_parts.push(
  149. "耐久レベル(SUV)[#{suv}]",
  150. "部位[#{table_point[num_d1]}] : 損傷種別[#{damage_level}]"
  151. )
  152. end
  153. 6 return (header_parts + result_parts).join(separator)
  154. end
  155. # 表を振った結果の整形処理
  156. 1 TABLE_ROLL_RESULT_FORMATTER = lambda do |table, result|
  157. 9 [table.name, result.sum, result.content].join(' > ')
  158. end
  159. # 表の集合
  160. TABLES = {
  161. 1 'CC' => DiceTable::RangeTable.new(
  162. 'クリティカルチャート',
  163. '1D10',
  164. [
  165. [1, '相手は知覚系に多大なダメージを受けた。PERを1にして頭部にHWのダメージ、および心理チェック。'],
  166. [2, '相手の運動神経を断ち切った。DEXを1にして腕部にHWのダメージ、および心理チェック。さらに腕に持っていた武器などは落としてしまう。'],
  167. [3, '相手の移動手段は完全に奪われた。REFを1にして脚部にHWダメージと心理チェック。また、次回からのこちらの攻撃は必ず命中する。'],
  168. [4..5, '相手の急所に命中。激痛のため気絶した上、胴にHWダメージ。'],
  169. [6, '効果的な一撃。胴にHWダメージ。心理チェック。'],
  170. [7, '効果的な一撃。胴にMOダメージ。心理チェック。'],
  171. [8..10, '君の一撃は相手の中枢を完全に破壊した。即死である。'],
  172. ],
  173. &TABLE_ROLL_RESULT_FORMATTER
  174. ),
  175. 'ACL' => DiceTable::RangeTable.new(
  176. 'アクシデントチャート(射撃・投擲)',
  177. '1D10',
  178. [
  179. [1..7, 'ささいなミス。特にペナルティーはない。'],
  180. [8, '不発、またはジャム。弾を取り出さねばならない物は次のターンは射撃できない。'],
  181. [9, 'ささいな故障。可能なら次のターンから個別武器のスキルロールで修理を行える。'],
  182. [10, '武器の暴発、または爆発。頭部HWの心理効果ロール。さらに、その武器は破壊されPERとDEXのどちらか、または両方に計2ポイントのマイナスを与える。(遠隔操作の場合、射手への被害は無し)'],
  183. ],
  184. &TABLE_ROLL_RESULT_FORMATTER
  185. ),
  186. 'ACS' => DiceTable::RangeTable.new(
  187. 'アクシデントチャート(格闘)',
  188. '1D10',
  189. [
  190. [1..3, '足を滑らせて転倒し、起き上がるまで相手に+20の命中修正を与える。'],
  191. [4..6, '手を滑らせて、武器を落とす。素手の時は関係ない。'],
  192. [7..9, '使用武器の破壊。素手戦闘のときはMWのダメージを受ける。'],
  193. [10, '手を滑らせ、不幸にも武器は飛んでいき、5m以内に人がいれば誰かに刺さるか、または打撃を与えるかもしれない。ランダムに決定し、普通どおり判定を続ける。素手のときは関係ない。'],
  194. ],
  195. &TABLE_ROLL_RESULT_FORMATTER
  196. ),
  197. }.freeze
  198. end
  199. end
  200. end

lib/bcdice/game_system/MetalHeadExtream.rb

98.03% lines covered

92.31% branches covered

254 relevant lines. 249 lines covered and 5 lines missed.
104 total branches, 96 branches covered and 8 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MetalHeadExtream < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'MetalHeadExtream'
  7. # ゲームシステム名
  8. 1 NAME = 'メタルヘッドエクストリーム'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'めたるへつとえくすとりいむ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ◆判定:ARn or SRn[*/a][@b][Ac][Ld][!M]  []内省略可。
  14. 「n」で判定値、「*/a」でロール修正を指定。複数回指定可。
  15. 「@b」でアクシデント値、省略時は「96」。
  16. 「Ac」で高度なロール。「2、4、8」のみ指定可能。
  17. 「Ld」でラックポイント、「!M」でパンドラ《ミューズ》。
  18. 【書式例】
  19. AR84/2@99!M → 判定値84のAR1/2。アクシデント値99、パンドラ《ミューズ》。
  20. SR40*2A2L1@99 → 判定値80のSR、高度なロール2倍、ラック1点。
  21. ◆命中部位表:(命中部位)HIT[n]  以降、ROC時は[n]を指定。
  22. HU:人間  BK:バイク  WA:ワゴン  SC:シェルキャリア  BG:バギー
  23. IN:インセクター  PT:ポケットタンク  HT:ホバータンク  TA:戦車
  24. AC:装甲車  HE:ヘリ  TR:トレーラー  VT:VTOL  BO:ボート
  25. CS:通常、格闘型コンバットシェル  TH:可変、重コンバットシェル
  26. AM:オートモビル  GD:ガンドック  HC:ホバークラフト
  27. BI:自転車  BT:バトルトレーラー  AI:エアクラフト
  28. ◆戦闘結果表:SUV(A~Z)n  【書式例】SUVM100
  29. ◆損傷効果表:(命中部位)DMG(損傷種別)  【書式例】TDMGH
  30. H:頭部  T:胴部  A:腕部  L:脚部  M:心理  E:電子
  31. B:メカニック本体  P:パワープラント  D:ドライブ
  32. (損傷種別) L:LW  M:MW  H:HW  O:MO
  33. ◆クリティカル表:CRT[n]
  34. ◆アクシデント表:(種別)AC[n]
  35. G:格闘  S:射撃、投擲  M:心理  E:電子
  36. ◆メカニック事故表:(場所)MA[n][+m]  「+m」で修正を指定。
  37. A:空中  S:水上、水中  L:地上
  38. 【マスコンバット】
  39. ストラテジーイベントチャート:SEC
  40. NPC攻撃処理チャート:NAC  敗者運命チャート:LDC
  41. 【各種表】
  42. 荒野ランダムエンカウント表:WENC[n]
  43. MESSAGETEXT
  44. 1 register_prefix(
  45. '[AS]R',
  46. '(HU|BK|WA|SC|BG|IN|PT|HT|TA|AC|HE|TR|VT|BO|CS|TH|AM|GD|HC|BI|BT|AI)HIT',
  47. 'SUV[A-Z]', '[HTALMEBPD]DMG[LMHO]',
  48. 'CRT', '[GSME]AC', '[ASL]MA',
  49. 'SEC', 'NAC', 'LDC', '[W]ENC'
  50. )
  51. 1 def eval_game_system_specific_command(command)
  52. text =
  53. 106 else: 0 case command.upcase
  54. when: 36 when %r{([AS])R(\d+)(([*/]\d+)*)?(((@|A|L)\d+)*)(!M)?$}i
  55. 36 m = Regexp.last_match
  56. 36 type = m[1]
  57. 36 target = m[2].to_i
  58. 36 modify = get_value(1, m[3])
  59. 36 paramText = m[5] || ''
  60. 36 isMuse = !m[8].nil? # パンドラ《ミューズ》
  61. 36 accidentValue = 96
  62. 36 advancedRoll = 1
  63. 36 luckPoint = 0
  64. 36 params = paramText.scan(/(.)(\d+)/)
  65. 36 params.each do |marker, value|
  66. 31 accidentValue, advancedRoll, luckPoint = get_roll_parameter(accidentValue, advancedRoll, luckPoint, marker, value)
  67. end
  68. 36 checkRoll(type, target, modify, accidentValue, advancedRoll, luckPoint, isMuse)
  69. when: 27 when /(HU|BK|WA|SC|BG|IN|PT|HT|TA|AC|HE|TR|VT|BO|CS|TH|AM|GD|HC|BI|BT|AI)HIT(\d+)?/i
  70. 27 hitPart = Regexp.last_match(1)
  71. 27 roc = (Regexp.last_match(2) || 0).to_i
  72. 27 get_hit_table(hitPart, roc)
  73. when: 8 when /SUV([A-Z])(\d+)/i
  74. 8 armorGrade = Regexp.last_match(1)
  75. 8 damage = Regexp.last_match(2).to_i
  76. 8 get_SUV_table(armorGrade, damage)
  77. when: 9 when /([HTALMEBPD])DMG([LMHO])/i
  78. 9 hitPart = Regexp.last_match(1)
  79. 9 damageStage = Regexp.last_match(2)
  80. 9 get_damageEffect_table(hitPart, damageStage)
  81. when: 5 when /CRT(\d+)?/i
  82. 5 roc = (Regexp.last_match(1) || 0).to_i
  83. 5 get_critical_table(roc)
  84. when: 4 when /([GSME])AC(\d+)?/i
  85. 4 damageType = Regexp.last_match(1)
  86. 4 roc = (Regexp.last_match(2) || 0).to_i
  87. 4 get_accident_table(damageType, roc)
  88. when: 6 when /([ASL])MA(\d+)?(\+(\d+))?/i
  89. 6 locationType = Regexp.last_match(1)
  90. 6 roc = (Regexp.last_match(2) || 0).to_i
  91. 6 correction = (Regexp.last_match(4) || 0).to_i
  92. 6 get_mechanicAccident_table(locationType, roc, correction)
  93. when: 2 when 'SEC'
  94. 2 get_strategyEvent_chart
  95. when: 2 when 'NAC'
  96. 2 get_NPCAttack_chart
  97. when: 2 when 'LDC'
  98. 2 get_loserDestiny_chart
  99. when: 5 when /(W)ENC(\d+)?/i
  100. 5 locationType = Regexp.last_match(1)
  101. 5 roc = (Regexp.last_match(2) || 0).to_i
  102. 5 get_randomEncounter_table(locationType, roc)
  103. end
  104. 106 return text
  105. end
  106. 1 def checkRoll(rollText, target, modify, accidentValue, advancedRoll, luckPoint, isMuse)
  107. 36 rollTarget = (target * modify / advancedRoll * (2**luckPoint)).to_i
  108. 36 dice = @randomizer.roll_once(100)
  109. 36 resultText, successValue = getRollResultTextAndSuccesValue(dice, advancedRoll, rollTarget, accidentValue, isMuse)
  110. 36 resultText += " 達成値:#{successValue}"
  111. 36 complementText = "ACC:#{accidentValue}"
  112. 36 then: 8 else: 28 complementText += ", ADV:\*#{advancedRoll}" if advancedRoll > 1
  113. 36 then: 8 else: 28 complementText += ", LUC:#{luckPoint}" if luckPoint > 0
  114. 36 then: 26 if modify >= 1
  115. 26 modifyText = modify.to_i.to_s
  116. else: 10 else
  117. 10 modifyText = "1\/#{(1 / modify).to_i}"
  118. end
  119. 36 formulaText = getFormulaText(target, modify, advancedRoll, luckPoint)
  120. 36 result = "#{rollText}R#{modifyText}(#{complementText}):1D100<=#{rollTarget}#{formulaText} > [#{dice}] #{resultText}"
  121. 36 then: 4 else: 32 result += " 《ミューズ》" if isMuse
  122. 36 return result
  123. end
  124. 1 def get_roll_parameter(accident, advanced, luck, marker, value)
  125. 31 value = value.to_i
  126. 31 else: 0 case marker
  127. when: 10 when '@'
  128. 10 accident = value
  129. when: 11 when 'A'
  130. 11 then: 9 else: 2 advanced = value if [2, 4, 8].include?(value)
  131. when: 10 when 'L'
  132. 10 luck = value
  133. end
  134. 31 return accident, advanced, luck
  135. end
  136. 1 def getRollResultTextAndSuccesValue(dice, advancedRoll, rollTarget, accidentValue, isMuse)
  137. 36 successValue = 0
  138. 36 then: 3 else: 33 if dice >= accidentValue
  139. 3 resultText = "失敗(アクシデント)"
  140. 3 return resultText, successValue
  141. end
  142. 33 then: 10 else: 23 if dice > rollTarget
  143. 10 resultText = "失敗"
  144. 10 return resultText, successValue
  145. end
  146. 23 dig1 = dice - ((dice / 10).to_i * 10)
  147. 23 then: 4 if isMuse
  148. 4 isCritical = (dig1 <= 1)
  149. else: 19 else
  150. 19 isCritical = (dig1 == 1)
  151. end
  152. 23 resultText = "成功"
  153. 23 then: 5 else: 18 resultText += "(クリティカル)" if isCritical
  154. 23 successValue = dice * advancedRoll
  155. 23 return resultText, successValue
  156. end
  157. 1 def getFormulaText(target, modify, advancedRoll, luckPoint)
  158. 36 formulaText = target.to_s
  159. 36 then: 4 else: 32 formulaText += "\*#{modify.to_i}" if modify > 1
  160. 36 then: 10 else: 26 formulaText += "\/#{(1 / modify).to_i}" if modify < 1
  161. 36 then: 8 else: 28 formulaText += "\/#{advancedRoll}" if advancedRoll > 1
  162. 36 then: 8 else: 28 formulaText += "\*#{2**luckPoint}" if luckPoint > 0
  163. 36 then: 16 else: 20 return "" if formulaText == target.to_s
  164. 20 return "[#{formulaText}]"
  165. end
  166. 1 def get_hit_table(hitPart, roc)
  167. 27 case hitPart
  168. when: 6 when 'HU'
  169. 6 name = '命中部位表:人間'
  170. table = [
  171. 6 [1, '胴部(クリティカル)'],
  172. [2, '頭部'],
  173. [3, '左腕部'],
  174. [4, '右腕部'],
  175. [5, '胴部'],
  176. [6, '胴部'],
  177. [7, '胴部'],
  178. [8, '胴部'],
  179. [9, '脚部'],
  180. [10, '脚部']
  181. ]
  182. when: 1 when 'BK'
  183. 1 name = '命中部位表:バイク'
  184. table = [
  185. 1 [1, '本体(クリティカル)'],
  186. [2, '本体'],
  187. [3, '本体'],
  188. [4, '本体'],
  189. [5, 'パワープラント'],
  190. [6, 'ドライブ'],
  191. [7, 'ドライブ'],
  192. [8, '兵装・貨物'],
  193. [9, '乗員'],
  194. [10, '乗員']
  195. ]
  196. when: 1 when 'WA'
  197. 1 name = '命中部位表:ワゴン'
  198. table = [
  199. 1 [1, '本体(クリティカル)'],
  200. [2, '本体'],
  201. [3, '本体'],
  202. [4, '本体'],
  203. [5, '本体'],
  204. [6, '本体'],
  205. [7, 'パワープラント'],
  206. [8, 'ドライブ'],
  207. [9, '兵装・貨物'],
  208. [10, '乗員']
  209. ]
  210. when: 1 when 'SC'
  211. 1 name = '命中部位表:シェルキャリア'
  212. table = [
  213. 1 [1, '本体(クリティカル)'],
  214. [2, '本体'],
  215. [3, '本体'],
  216. [4, '本体'],
  217. [5, '本体'],
  218. [6, '本体'],
  219. [7, 'パワープラント'],
  220. [8, 'ドライブ'],
  221. [9, '兵装・貨物'],
  222. [10, '乗員']
  223. ]
  224. when: 1 when 'BG'
  225. 1 name = '命中部位表:バギー'
  226. table = [
  227. 1 [1, '本体(クリティカル)'],
  228. [2, '本体'],
  229. [3, '本体'],
  230. [4, '本体'],
  231. [5, '本体'],
  232. [6, 'パワープラント'],
  233. [7, 'ドライブ'],
  234. [8, '兵装・貨物'],
  235. [9, '兵装・貨物'],
  236. [10, '乗員']
  237. ]
  238. when: 1 when 'IN'
  239. 1 name = '命中部位表:インセクター'
  240. table = [
  241. 1 [1, '本体(クリティカル)'],
  242. [2, '本体'],
  243. [3, '本体'],
  244. [4, '本体'],
  245. [5, '本体'],
  246. [6, 'パワープラント'],
  247. [7, 'ドライブ'],
  248. [8, 'ドライブ'],
  249. [9, 'ドライブ'],
  250. [10, '乗員']
  251. ]
  252. when: 1 when 'PT'
  253. 1 name = '命中部位表:ポケットタンク'
  254. table = [
  255. 1 [1, '本体(クリティカル)'],
  256. [2, '本体'],
  257. [3, '本体'],
  258. [4, '本体'],
  259. [5, '本体'],
  260. [6, 'パワープラント'],
  261. [7, 'パワープラント'],
  262. [8, 'ドライブ'],
  263. [9, 'ドライブ'],
  264. [10, '兵装・貨物']
  265. ]
  266. when: 1 when 'HT'
  267. 1 name = '命中部位表:ホバータンク'
  268. table = [
  269. 1 [1, '本体(クリティカル)'],
  270. [2, '本体'],
  271. [3, '本体'],
  272. [4, '本体'],
  273. [5, '本体'],
  274. [6, '本体'],
  275. [7, 'パワープラント'],
  276. [8, 'ドライブ'],
  277. [9, '兵装・貨物'],
  278. [10, '兵装・貨物']
  279. ]
  280. when: 1 when 'TA'
  281. 1 name = '命中部位表:戦車'
  282. table = [
  283. 1 [1, '本体(クリティカル)'],
  284. [2, '本体'],
  285. [3, '本体'],
  286. [4, '本体'],
  287. [5, '本体'],
  288. [6, 'パワープラント'],
  289. [7, 'ドライブ'],
  290. [8, 'ドライブ'],
  291. [9, '兵装・貨物'],
  292. [10, '兵装・貨物']
  293. ]
  294. when: 1 when 'AC'
  295. 1 name = '命中部位表:装甲車'
  296. table = [
  297. 1 [1, '本体(クリティカル)'],
  298. [2, '本体'],
  299. [3, '本体'],
  300. [4, '本体'],
  301. [5, '本体'],
  302. [6, 'パワープラント'],
  303. [7, 'ドライブ'],
  304. [8, 'ドライブ'],
  305. [9, '兵装・貨物'],
  306. [10, '兵装・貨物']
  307. ]
  308. when: 1 when 'HE'
  309. 1 name = '命中部位表:ヘリ'
  310. table = [
  311. 1 [1, '本体(クリティカル)'],
  312. [2, '本体'],
  313. [3, '本体'],
  314. [4, '本体'],
  315. [5, 'パワープラント'],
  316. [6, 'ドライブ'],
  317. [7, 'ドライブ'],
  318. [8, '兵装・貨物'],
  319. [9, '兵装・貨物'],
  320. [10, '乗員']
  321. ]
  322. when: 1 when 'TR'
  323. 1 name = '命中部位表:トレーラー'
  324. table = [
  325. 1 [1, '本体(クリティカル)'],
  326. [2, '本体'],
  327. [3, '本体'],
  328. [4, '本体'],
  329. [5, 'パワープラント'],
  330. [6, 'ドライブ'],
  331. [7, '兵装・カーゴ'],
  332. [8, '兵装・カーゴ'],
  333. [9, '兵装・カーゴ'],
  334. [10, '乗員']
  335. ]
  336. when: 1 when 'VT'
  337. 1 name = '命中部位表:VTOL'
  338. table = [
  339. 1 [1, '本体(クリティカル)'],
  340. [2, '本体'],
  341. [3, '本体'],
  342. [4, '本体'],
  343. [5, '本体'],
  344. [6, 'パワープラント'],
  345. [7, 'ドライブ'],
  346. [8, '兵装・貨物'],
  347. [9, '兵装・貨物'],
  348. [10, '乗員']
  349. ]
  350. when: 1 when 'BO'
  351. 1 name = '命中部位表:ボート'
  352. table = [
  353. 1 [1, '本体(クリティカル)'],
  354. [2, '本体'],
  355. [3, '本体'],
  356. [4, '本体'],
  357. [5, '本体'],
  358. [6, '本体'],
  359. [7, '本体'],
  360. [8, 'パワープラント'],
  361. [9, 'ドライブ'],
  362. [10, '兵装・貨物']
  363. ]
  364. when: 1 when 'CS'
  365. 1 name = '命中部位表:通常・格闘型コンバットシェル'
  366. table = [
  367. 1 [1, '本体(クリティカル)'],
  368. [2, '本体'],
  369. [3, '本体'],
  370. [4, '本体'],
  371. [5, '本体'],
  372. [6, '本体'],
  373. [7, 'ザック'],
  374. [8, 'ドライブ'],
  375. [9, '兵装・貨物'],
  376. [10, '兵装・貨物']
  377. ]
  378. when: 1 when 'TH'
  379. 1 name = '命中部位表:可変・重コンバットシェル'
  380. table = [
  381. 1 [1, '本体(クリティカル)'],
  382. [2, '本体'],
  383. [3, '本体'],
  384. [4, '本体'],
  385. [5, '本体'],
  386. [6, '本体'],
  387. [7, 'ドライブ'],
  388. [8, 'ドライブ'],
  389. [9, '兵装・貨物'],
  390. [10, '兵装・貨物']
  391. ]
  392. when: 1 when 'AM'
  393. 1 name = '命中部位表:オートモビル'
  394. table = [
  395. 1 [1, '本体(クリティカル)'],
  396. [2, '本体'],
  397. [3, '本体'],
  398. [4, '本体'],
  399. [5, '本体'],
  400. [6, 'パワープラント'],
  401. [7, 'ドライブ'],
  402. [8, '兵装・貨物'],
  403. [9, '兵装・貨物'],
  404. [10, '乗員']
  405. ]
  406. when: 1 when 'GD'
  407. 1 name = '命中部位表:ガンドック'
  408. table = [
  409. 1 [1, '本体(クリティカル)'],
  410. [2, '本体'],
  411. [3, '本体'],
  412. [4, '本体'],
  413. [5, '本体'],
  414. [6, 'パワープラント'],
  415. [7, 'ドライブ'],
  416. [8, 'ドライブ'],
  417. [9, '兵装・貨物'],
  418. [10, '乗員']
  419. ]
  420. when: 1 when 'HC'
  421. 1 name = '命中部位表:ホバークラフト'
  422. table = [
  423. 1 [1, '本体(クリティカル)'],
  424. [2, '本体'],
  425. [3, '本体'],
  426. [4, '本体'],
  427. [5, 'パワープラント'],
  428. [6, 'パワープラント'],
  429. [7, 'ドライブ'],
  430. [8, '兵装・貨物'],
  431. [9, '乗員'],
  432. [10, '乗員']
  433. ]
  434. when: 1 when 'BI'
  435. 1 name = '命中部位表:自転車'
  436. table = [
  437. 1 [1, '本体(クリティカル)'],
  438. [2, '本体'],
  439. [3, '本体'],
  440. [4, '本体'],
  441. [5, '本体'],
  442. [6, 'パワープラント'],
  443. [7, 'ドライブ'],
  444. [8, '兵装・貨物'],
  445. [9, '兵装・貨物'],
  446. [10, '乗員']
  447. ]
  448. when: 1 when 'BT'
  449. 1 name = '命中部位表:バトルトレーラー'
  450. table = [
  451. 1 [1, '本体(クリティカル)'],
  452. [2, '本体'],
  453. [3, '本体'],
  454. [4, '本体'],
  455. [5, '本体'],
  456. [6, 'パワープラント'],
  457. [7, 'ドライブ'],
  458. [8, '兵装・貨物'],
  459. [9, '兵装・貨物'],
  460. [10, '乗員']
  461. ]
  462. when: 1 when 'AI'
  463. 1 name = '命中部位表:エアクラフト'
  464. table = [
  465. 1 [1, '本体(クリティカル)'],
  466. [2, '本体'],
  467. [3, '本体'],
  468. [4, '本体'],
  469. [5, '本体'],
  470. [6, 'パワープラント'],
  471. [7, 'ドライブ'],
  472. [8, '兵装・貨物'],
  473. [9, '兵装・貨物'],
  474. [10, '乗員']
  475. ]
  476. else: 0 else
  477. return nil
  478. end
  479. 27 return get_MetalHeadExtream_1d10_table_result(name, table, roc)
  480. end
  481. 1 def get_SUV_table(armorGrade, damage)
  482. 8 name = '戦闘結果表'
  483. table = [
  484. 8 [0, 1, 6, 16, 26, 36],
  485. [0, 1, 6, 26, 36, 46],
  486. [0, 1, 16, 26, 46, 56],
  487. [1, 6, 26, 36, 56, 76],
  488. [1, 16, 36, 46, 66, 76],
  489. [1, 26, 36, 56, 76, 86],
  490. [1, 36, 56, 66, 76, 96],
  491. [1, 56, 76, 86, 96, 106],
  492. [1, 66, 86, 96, 106, 116],
  493. [1, 66, 86, 96, 116, 136],
  494. [1, 76, 96, 106, 126, 156],
  495. [1, 76, 96, 116, 146, 166],
  496. [1, 86, 106, 126, 166, 176],
  497. [1, 106, 126, 136, 176, 196],
  498. [1, 106, 126, 146, 186, 206],
  499. [1, 116, 136, 156, 196, 206],
  500. [1, 126, 146, 166, 206, 226],
  501. [1, 126, 146, 176, 226, 246],
  502. [1, 136, 156, 186, 246, 266],
  503. [1, 156, 176, 206, 246, 286],
  504. [1, 156, 176, 206, 266, 306],
  505. [1, 166, 186, 206, 286, 346],
  506. [1, 176, 196, 246, 326, 366],
  507. [1, 196, 226, 266, 346, 386],
  508. [1, 206, 226, 286, 366, 406],
  509. [1, 226, 246, 306, 386, 406]
  510. ]
  511. 8 armorIndex = ('A'..'Z').to_a.index(armorGrade)
  512. 8 damageInfo = table[armorIndex]
  513. 8 woundRanks = ['無傷', 'LW(軽傷)', 'MW(中傷)', 'HW(重傷)', 'MO(致命傷)', 'KL(死亡)']
  514. 8 woundText = ""
  515. 8 damageInfo.each_with_index do |rate, index|
  516. 29 then: 7 else: 22 break if rate > damage
  517. 22 woundText = woundRanks[index]
  518. end
  519. 8 return "#{name}(#{armorGrade}):#{damage} > #{woundText}"
  520. end
  521. 1 def get_damageEffect_table(hitPart, damageStage)
  522. 9 damageInfos = [['L', '(LW)'],
  523. ['M', '(MW)'],
  524. ['H', '(HW)'],
  525. ['O', '(MO)']]
  526. 30 index = damageInfos.index { |i| i.first == damageStage }
  527. 9 then: 0 else: 9 return nil if index == -1
  528. 9 damageIndex = index + 1
  529. 9 damageText = damageInfos[index][1]
  530. 9 case hitPart
  531. when: 1 when 'H'
  532. 1 name = '対人損傷効果表:頭部'
  533. table = [
  534. 1 [1, 'ダメージ修正+10。'],
  535. [2, 'ダメージ修正+10。【PER】のAR、【PER】がベースアビリティのスキルのSRにSR1/2のロール修正。'],
  536. [3, 'ダメージ修正+20。【PER】のAR、【PER】がベースアビリティのスキルのSRにSR1/4のロール修正。'],
  537. [4, 'ダメージ修正+30。[死亡]。頭部がサイバーの場合は[戦闘不能]。']
  538. ]
  539. when: 1 when 'T'
  540. 1 name = '対人損傷効果表:胴部'
  541. table = [
  542. 1 [1, 'ダメージ修正+10。'],
  543. [2, 'ダメージ修正+10。【DEX】のAR、【DEX】がベースアビリティのスキルのSRにSR1/2のロール修正。'],
  544. [3, 'ダメージ修正+20。【DEX】のAR、【DEX】がベースアビリティのスキルのSRにSR1/4のロール修正。'],
  545. [4, 'ダメージ修正+30。[戦闘不能]。']
  546. ]
  547. when: 1 when 'A'
  548. 1 name = '対人損傷効果表:腕部'
  549. table = [
  550. 1 [1, 'ダメージ修正+10。'],
  551. [2, 'ダメージ修正+10。損傷した腕を使用する、また両腕を使用する行動にSR1/2のロール修正。'],
  552. [3, 'ダメージ修正+20。損傷した腕を使用する、また両腕を使用する行動にSR1/4のロール修正。'],
  553. [4, 'ダメージ修正+30。損傷した腕を使用する、また両腕を使用する行動不可。']
  554. ]
  555. when: 1 when 'L'
  556. 1 name = '対人損傷効果表:脚部'
  557. table = [
  558. 1 [1, 'ダメージ修正+10。'],
  559. [2, 'ダメージ修正+10。【REF】のAR、【REF】がベースアビリティのスキルのSRにSR1/2のロール修正。'],
  560. [3, 'ダメージ修正+20。【REF】のAR、【REF】がベースアビリティのスキルのSRにSR1/4のロール修正。【MV】が1/2。'],
  561. [4, 'ダメージ修正+30。[戦闘不能]。']
  562. ]
  563. when: 1 when 'M'
  564. 1 name = '心理損傷効果表'
  565. table = [
  566. 1 [1, 'ダメージ修正+10。焦り。効果は特になし。シーン終了で自然回復。'],
  567. [2, 'ダメージ修正+20。混乱。1シーン、すべてのロールがSR1/2となる。シーン終了で自然回復。'],
  568. [3, 'ダメージ修正+30。恐怖。1シーン、すべてのロールがSR1/4となる。シーン終了で自然回復。'],
  569. [4, 'ダメージ修正+50。喪失。[戦闘不能]。シーン終了で自然回復。']
  570. ]
  571. when: 1 when 'E'
  572. 1 name = '電子損傷効果表'
  573. table = [
  574. 1 [1, 'ダメージ修正+10。処理落ち。効果は特になし。'],
  575. [2, 'ダメージ修正+20。ノイズ。1シーン、キャラクターならすべてのロールが、アイテムならそれを使用したロールが1/2となる。'],
  576. [3, 'ダメージ修正+30。恐怖。1シーン、キャラクターならすべてのロールが、アイテムならそれを使用したロールが1/4となる。'],
  577. [4, 'ダメージ修正+50。クラッシュ。キャラクターなら[戦闘不能]。アイテムなら1シナリオ中、使用不可。']
  578. ]
  579. when: 1 when 'B'
  580. 1 name = 'メカニック損傷効果表:本体'
  581. table = [
  582. 1 [1, 'ダメージ修正+10。'],
  583. [2, 'ダメージ修正シフト1。修理費がフレーム価格の1/4かかる。'],
  584. [3, 'ダメージ修正シフト2。修理費がフレーム価格の1/2かかる。'],
  585. [4, 'ダメージ修正シフト3。移動不能。修理費がフレーム価格と同じだけかかる。走行中なら事故表を振ること。']
  586. ]
  587. when: 1 when 'P'
  588. 1 name = 'メカニック損傷効果表:パワープラント'
  589. table = [
  590. 1 [1, 'ダメージ修正+10。'],
  591. [2, 'ダメージ修正+10。メカニックの【MV】が1/2になる。修理費がパワープラント価格の1/4かかる。'],
  592. [3, 'ダメージ修正+20。メカニックの【MV】が1/4になる。修理費がパワープラント価格の1/2かかる。'],
  593. [4, 'ダメージ修正+30。移動不能。修理費がパワープラント価格と同じだけかかる。走行中なら事故表を振ること。']
  594. ]
  595. when: 1 when 'D'
  596. 1 name = 'メカニック損傷効果表:ドライブ'
  597. table = [
  598. 1 [1, 'ダメージ修正+10。'],
  599. [2, 'ダメージ修正+10。メカニックの【REF】が1/2になる。[メカニック]スキルにSR1/2の修正。修理費がドライブ価格の1/4かかる。'],
  600. [3, 'ダメージ修正+20。メカニックの【REF】が1/2になる。[メカニック]スキルにSR1/4の修正。修理費がドライブ価格の1/2かかる。'],
  601. [4, 'ダメージ修正+30。移動不能。修理費がドライブ価格と同じだけかかる。走行中なら事故表を振ること。']
  602. ]
  603. else: 0 else
  604. return nil
  605. end
  606. 9 text = get_table_by_number(damageIndex, table)
  607. 9 return "#{name}#{damageText} > #{text}"
  608. end
  609. 1 def get_critical_table(roc)
  610. 5 name = 'クリティカル表'
  611. table = [
  612. 5 [1, '特に追加被害は発生しない。'],
  613. [2, '対象はバランスを崩す。クリンナッププロセスまで、対象は命中ロールにSR1/2のロール修正を受ける。'],
  614. [3, '対象に隙を作る。クリンナッププロセスまで、対象はリアクションにSR1/2のロール修正を受ける。'],
  615. [4, '激しい一撃。最終火力に+20してダメージを算出すること。'],
  616. [5, '多大なダメージ。最終火力に+20してダメージを算出すること。'],
  617. [6, '弱点に直撃。対象の装甲値を無視してダメージを算出すること。'],
  618. [7, '効果的な一撃。対象の受ける損傷段階をシフト1する。'],
  619. [8, '致命的な一撃。対象の受ける損傷段階をシフト2する。'],
  620. [9, '中枢に直撃。対象の【SUV】を3ランク低いものとしてダメージを算出する。'],
  621. [10, '中枢を破壊。対象の装甲値を無視し、【SUV】を3ランク低いものとしてダメージを算出する。']
  622. ]
  623. 5 return get_MetalHeadExtream_1d10_table_result(name, table, roc)
  624. end
  625. 1 def get_accident_table(damageType, roc)
  626. 4 case damageType
  627. when: 1 when 'G'
  628. 1 name = '格闘アクシデント表'
  629. table = [
  630. 1 [1, '体勢を崩す。その攻撃は失敗する。'],
  631. [2, '体勢を崩す。その攻撃は失敗する。'],
  632. [3, '体勢を崩す。その攻撃は失敗する。'],
  633. [4, '転倒。格闘回避と機動回避にSR1/4、【MV】が半分に。'],
  634. [5, '転倒。格闘回避と機動回避にSR1/4、【MV】が半分に。'],
  635. [6, '転倒。格闘回避と機動回避にSR1/4、【MV】が半分に。'],
  636. [7, '武器が足下(0m離れたところ)に落ちる。素手のときは何もなし。'],
  637. [8, '武器が足下(0m離れたところ)に落ちる。素手のときは何もなし。'],
  638. [9, '武器が5m離れたところに落ちる。素手のときは関係ない。'],
  639. [10, '使用武器が壊れ、1シーン使用不可。']
  640. ]
  641. when: 1 when 'S'
  642. 1 name = '射撃/投擲アクシデント表'
  643. table = [
  644. 1 [1, 'ささいなミス。その攻撃は失敗する。'],
  645. [2, 'ささいなミス。その攻撃は失敗する。'],
  646. [3, 'ささいなミス。その攻撃は失敗する。'],
  647. [4, '射撃武器はジャム。投擲武器ならば武器が取り出せないなど、マイナーアクションを消費しなければその武器を使用できない。'],
  648. [5, '射撃武器はジャム。投擲武器ならば武器が取り出せないなど、マイナーアクションを消費しなければその武器を使用できない。'],
  649. [6, '射撃武器はジャム。投擲武器ならば武器が取り出せないなど、マイナーアクションを消費しなければその武器を使用できない。'],
  650. [7, '故障。メジャーアクションで【DEX】のSR1のロールに成功しなければ、その武器を使用できない。'],
  651. [8, '故障。メジャーアクションで【DEX】のSR1のロールに成功しなければ、その武器を使用できない。'],
  652. [9, '破壊。以後、その武器は使用できない。'],
  653. [10, '武器の暴発。固定火力100のダメージを、装甲値無視で武器を持っていた腕(両手なら両手)、または兵装・貨物に受ける。']
  654. ]
  655. when: 1 when 'M'
  656. 1 name = '心理攻撃アクシデント表'
  657. table = [
  658. 1 [1, '集中失敗。攻撃は失敗する。'],
  659. [2, '集中失敗。攻撃は失敗する。'],
  660. [3, '集中失敗。攻撃は失敗する。'],
  661. [4, '思考ノイズ。クリンナップまですべてのリアクションにSR1/2。'],
  662. [5, '思考ノイズ。クリンナップまですべてのリアクションにSR1/2。'],
  663. [6, '思考ノイズ。クリンナップまですべてのリアクションにSR1/2。'],
  664. [7, 'EXの暴走。頭部に装甲値無視、固定火力60のダメージを受ける。'],
  665. [8, 'EXの暴走。頭部に装甲値無視、固定火力60のダメージを受ける。'],
  666. [9, '感情暴走。攻撃に使用したマニューバが1シーン使用不可。'],
  667. [10, 'トラウマの再現。装甲値無視、固定火力100の心理ダメージを受ける。']
  668. ]
  669. when: 1 when 'E'
  670. 1 name = '電子攻撃アクシデント表'
  671. table = [
  672. 1 [1, 'ショック。攻撃は失敗する。'],
  673. [2, 'ショック。攻撃は失敗する。'],
  674. [3, 'ショック。攻撃は失敗する。'],
  675. [4, 'ノイズ発生。クリンナップまで電子攻撃のリアクションにSR1/2。'],
  676. [5, 'ノイズ発生。クリンナップまで電子攻撃のリアクションにSR1/2。'],
  677. [6, 'ノイズ発生。クリンナップまで電子攻撃のリアクションにSR1/2。'],
  678. [7, 'ソフトウェア障害。攻撃に使用したソフトが1シーン使用不可。'],
  679. [8, 'ソフトウェア障害。攻撃に使用したソフトが1シーン使用不可。'],
  680. [9, 'ハードウェア障害。装甲値無視、固定火力80の電子ダメージを受ける。'],
  681. [10, '信号逆流。装甲値無視、固定火力100の心理ダメージを受ける。']
  682. ]
  683. else: 0 else
  684. return nil
  685. end
  686. 4 return get_MetalHeadExtream_1d10_table_result(name, table, roc)
  687. end
  688. 1 def get_mechanicAccident_table(locationType, roc, correction)
  689. 6 case locationType
  690. when: 2 when 'A'
  691. 2 name = '空中メカニック事故表'
  692. table = [
  693. 2 [3, '兵装/貨物。メカニックが装備している一番ENCの大きい武器ひとつが戦闘終了時まで使用不能になる。武器がない場合はメカニックオプションが使用不能になり、それもない場合は一番ENCの重い貨物(乗客をのぞく)が失われる。'],
  694. [6, '操作不能。メカニック本体にMWダメージ。操縦者は適切な[メカニック]スキルでSR1/4のロールを行い、成功したら体勢を立て直せる。失敗した場合、次のクリンナッププロセスまで、回避をふくめた一切の行動を取ることができない。'],
  695. [8, '不時着。メカニック本体にHWダメージ。次のクリンナッププロセスまで、回復をふくめた一切の行動を取ることができない。'],
  696. [9, '墜落。メカニック本体にMOダメージ。すべての乗員は、墜落のショックによってランダムな部位に〈物〉155の固定ダメージを受ける。このダメージは機動回避可能である。'],
  697. [10, '爆発。メカニックが爆発し、完全に破壊される。すべての乗員は、爆発と落下によって胴体に〈熱〉205の固定ダメージを受ける。このダメージは機動回避可能だが、SRに1/4の修正がある。']
  698. ]
  699. when: 2 when 'S'
  700. 2 name = '水上/水中メカニック事故表'
  701. table = [
  702. 2 [3, '横揺れ。次のクリンナッププロセスまで、このメカニックに乗っているキャラクターの行うすべての[メカニック]ロールに1/2の修正が与えられる。'],
  703. [6, '兵装/貨物。メカニックが装備している一番ENCの大きい武器ひとつが戦闘終了時まで使用不能になる。武器がない場合はメカニックオプションが使用不能になり、それもない場合は一番ENCの重い貨物(乗客をのぞく)が失われる。'],
  704. [8, '横転。メカニック本体にMWダメージ。操縦者は適切な[メカニック]スキルでSR1/4のロールを行い、成功したら体勢を立て直せる。失敗した場合、次のクリンナッププロセスまで、回避をふくめた一切の行動を取ることができない。'],
  705. [9, '激突。メカニック本体に〈物〉255の固定ダメージ。'],
  706. [10, '爆発。メカニックが爆発し、完全に破壊される。すべての乗員は、爆発によって胴体に〈熱〉155の固定ダメージを受ける。このダメージは機動回避可能だが、SRに1/4の修正がある。']
  707. ]
  708. when: 2 when 'L'
  709. 2 name = '地上メカニック事故表'
  710. table = [
  711. 2 [3, '接触。メカニック本体にLWダメージ。'],
  712. [6, '兵装/貨物。メカニックが装備している一番ENCの大きい武器ひとつが戦闘終了時まで使用不能になる。武器がない場合はメカニックオプションが使用不能になり、それもない場合は一番ENCの重い貨物(乗客をのぞく)が失われる。'],
  713. [8, 'スピン。メカニック本体にMWダメージ。操縦者は適切な[メカニック]スキルでSR1/4のロールを行い、成功したら体勢を立て直せる。失敗した場合、次のクリンナッププロセスまで、回避をふくめた一切の行動を取ることができない。'],
  714. [9, '激突。メカニック本体に〈物〉255の固定ダメージ。次のクリンナッププロセスまで、回避をふくめた一切の行動を取ることができない。'],
  715. [10, '爆発。メカニックが爆発し、完全に破壊される。すべての乗員は、爆発によって胴体に〈熱〉155の固定ダメージを受ける。このダメージは機動回避可能だが、SRに1/4の修正がある。']
  716. ]
  717. else: 0 else
  718. return nil
  719. end
  720. 6 dice = get_roc_dice(roc, 10)
  721. 6 diceText = dice.to_s
  722. 6 dice += correction
  723. 6 then: 1 else: 5 dice = 10 if dice > 10
  724. 6 then: 2 else: 4 diceText = "#{dice}[#{diceText}+#{correction}]" if correction > 0
  725. 6 tableText = get_table_by_number(dice, table)
  726. 6 text = "#{name}(#{diceText}) > #{tableText}"
  727. 6 return text
  728. end
  729. 1 def get_strategyEvent_chart
  730. 2 name = 'ストラテジーイベントチャート'
  731. table = [
  732. 2 [50, '特に何事もなかった。'],
  733. [53, 'スコール。種別:レーザーを装備している部隊の戦力はこのターン半減する。この効果は重複しない。'],
  734. [55, 'ただよう不安。味方ユニットはWILのAR1を行い、失敗すると士気の10%を失う。'],
  735. [57, '狙撃! 司令官キャラクターは胴体に〈物〉155点の固定ダメージを受ける。機動回避は可能。'],
  736. [60, '敵の猛烈な反撃! 味方ユニットはREFのAR1を行い、失敗するとこのターン、移動力がマイナス1。'],
  737. [63, '敵弾幕の隙を見いだす。このターン、味方ユニットは突破判定がSR2に。'],
  738. [65, '突破のチャンス。このターン、味方ユニットは移動力が1点上昇する。'],
  739. [67, '士気高揚。味方ユニットの士気がそれぞれ現在値の10%だけ回復する。'],
  740. [70, '敵陣崩壊。敵ユニットの中で士気がもっとも低いユニットが戦場から撤退する。複数いた場合、すべて撤退。PC、ゲストには効果なし。'],
  741. [73, '大声援。戦闘がどこかのハッカーによって衛星中継され、喝采を浴びる。'],
  742. [75, '雨/雪。種別;レーザーを部隊の戦力はこのターン半減する。この効果は重複しない。'],
  743. [77, '磁気嵐。このターン、種別:ミサイルは戦力に数えず、突撃に使用することもできない。'],
  744. [80, '膠着した戦況。このターン、味方ユニットは突破判定がSR1/2に。'],
  745. [83, 'メタルホッパー! 金属イナゴの襲来で視界をふさがれ、このラウンドは全てのMC射程が0となる。'],
  746. [85, '大竜巻! 飛行しているユニットの移動力は0となり、飛行ユニットはこのターン自分から突撃を行えない。'],
  747. [87, '通信の混乱。味方ユニットはINTのAR1を行い、失敗するとこのターン、移動力がマイナス1。'],
  748. [90, '幸運が微笑む。味方ユニットのラックポイントが1点ずつ回復。NPCには無効。'],
  749. [93, '致命的な狙撃! 司令官キャラクターは胴体に〈物〉205点の固定ダメージを受ける。機動回避は可能。'],
  750. [95, '敵の罠に落ちた。このターン、敵軍ユニットは移動力が1点上昇する。'],
  751. [97, '勝利の予感。味方ユニットの士気がそれぞれの現在値の20%だけ回復する。'],
  752. [99, '天変地異が襲いかかる! このターン、すべてのユニットは移動できない。'],
  753. [100, '大混乱。後2回振る。']
  754. ]
  755. 2 return get_MetalHeadExtream_1d100_table_result(name, table, 0)
  756. end
  757. 1 def get_NPCAttack_chart
  758. 2 name = 'NPC攻撃処理チャート'
  759. table = [
  760. 2 [5, '戦力の低い側だけが一方的に除去される。'],
  761. [8, '双方、一番戦力の少ないユニットひとつを除去する。'],
  762. [10, '戦力の高い側が最大戦力のユニットひとつを除去する。']
  763. ]
  764. 2 return get_MetalHeadExtream_1d10_table_result(name, table, 0)
  765. end
  766. 1 def get_loserDestiny_chart
  767. 2 name = '敗者運命チャート'
  768. table = [
  769. 2 [1, '奇跡的に無傷で生き延びた。いずれ復讐の機会もあるだろう。'],
  770. [2, 'ランダムな部位にLWを負う。'],
  771. [3, '戦力決定に使っていた武器が破壊される。'],
  772. [4, 'ランダムな部位にMWを負う。'],
  773. [5, '外見に影響するような傷を負う。治療するなら$3000。'],
  774. [6, 'ランダムな部位にHWを負う。'],
  775. [7, '着用している防具すべてが破壊される。衣服は壊れない。'],
  776. [8, 'ランダムな部位にMOを負う。'],
  777. [9, 'ランダムに決定した能力値ひとつを、永久に1点失う。'],
  778. [10, '残念ながら、君は死んでしまった。']
  779. ]
  780. 2 return get_MetalHeadExtream_1d10_table_result(name, table, 0)
  781. end
  782. 1 def get_randomEncounter_table(locationType, roc)
  783. 5 case locationType
  784. when: 5 when 'W'
  785. 5 name = '荒野ランダムエンカウント表'
  786. table = [
  787. 5 [80, '特に遭遇は発生しなかった'],
  788. [85, '1d10名のバンデッド'],
  789. [87, 'ヴェーダ・バウンサー1名に率いられた1d10+2(最低1)のヴェーダ・ソルジャー'],
  790. [89, '1d10+2体のウェーブコヨーテ'],
  791. [91, '1d10÷2体(最低1)のレーザーアント'],
  792. [93, '1d10-5体(最低1)のライトニングホーク'],
  793. [96, '1d10体のメタルホッパー'],
  794. [98, '1体のブラスビースト'],
  795. [100, '1d10÷3体(最低1)のサンドワーム']
  796. ]
  797. else: 0 else
  798. return nil
  799. end
  800. 5 return get_MetalHeadExtream_1d100_table_result(name, table, roc)
  801. end
  802. 1 def get_MetalHeadExtream_1d10_table_result(name, table, roc)
  803. 40 get_MetalHeadExtream_1dX_table_result(name, table, roc, 10)
  804. end
  805. 1 def get_MetalHeadExtream_1d100_table_result(name, table, roc)
  806. 7 get_MetalHeadExtream_1dX_table_result(name, table, roc, 100)
  807. end
  808. 1 def get_MetalHeadExtream_1dX_table_result(name, table, roc, diceMax)
  809. 47 dice = get_roc_dice(roc, diceMax)
  810. 47 text = get_table_by_number(dice, table)
  811. 47 return "#{name}(#{dice}) > #{text}"
  812. end
  813. 1 def get_roc_dice(roc, diceMax)
  814. 53 dice = roc
  815. 53 then: 2 else: 51 dice = diceMax if dice > diceMax
  816. 53 then: 34 else: 19 if dice == 0
  817. 34 dice = @randomizer.roll_once(diceMax)
  818. end
  819. 53 return dice
  820. end
  821. # 端数が使いたいので、parren_killer未使用
  822. 1 def get_value(originalValue, calculateText)
  823. 36 result = originalValue.to_f
  824. 36 calculateArray = (calculateText || '').scan(%r{[*/]\d*}) # 修正値を分割して配列へ
  825. 36 calculateArray.each do |i| # 配列内ループで補正率を計算
  826. 22 i =~ %r{([*/])(\d*)}i
  827. 22 then: 9 else: 13 result *= Regexp.last_match(2).to_i if Regexp.last_match(1) == '*'
  828. 22 then: 13 else: 9 result /= Regexp.last_match(2).to_i if Regexp.last_match(1) == '/'
  829. end
  830. 36 return result
  831. end
  832. end
  833. end
  834. end

lib/bcdice/game_system/MetallicGuardian.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/SRS'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class MetallicGuardian < SRS
  6. # 固有のコマンドの接頭辞を設定する
  7. 1 register_prefix('2D6', 'MG')
  8. # 成功判定のエイリアスコマンドを設定する
  9. 1 set_aliases_for_srs_roll('MG')
  10. # ゲームシステム名を返す
  11. # @return [String]
  12. # ゲームシステム名
  13. 1 NAME = 'メタリックガーディアンRPG'
  14. # ゲームシステム名の読みがな
  15. 1 SORT_KEY = 'めたりつくかあていあんRPG'
  16. # ゲームシステム識別子を返す
  17. # @return [String]
  18. # ゲームシステムの識別子
  19. 1 ID = 'MetallicGuardian'
  20. 1 HELP_MESSAGE = help_message()
  21. end
  22. end
  23. end

lib/bcdice/game_system/MonotoneMuseum.rb

98.36% lines covered

90.0% branches covered

61 relevant lines. 60 lines covered and 1 lines missed.
20 total branches, 18 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/dice_table/table'
  3. 1 require 'bcdice/dice_table/d66_range_table'
  4. 1 require 'bcdice/dice_table/d66_grid_table'
  5. 1 require 'bcdice/format'
  6. 1 module BCDice
  7. 1 module GameSystem
  8. 1 class MonotoneMuseum < Base
  9. # ゲームシステムの識別子
  10. 1 ID = 'MonotoneMuseum'
  11. # ゲームシステム名
  12. 1 NAME = 'モノトーンミュージアムRPG'
  13. # ゲームシステム名の読みがな
  14. 1 SORT_KEY = 'ものとおんみゆうしあむRPG'
  15. # ダイスボットの使い方
  16. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  17. ・判定
  18.  ・通常判定      2D6+m>=t[c,f]
  19.   修正値m,目標値t,クリティカル値c,ファンブル値fで判定ロールを行います。
  20.   クリティカル値、ファンブル値は省略可能です。([]ごと省略できます)
  21.   自動成功、自動失敗、成功、失敗を自動表示します。
  22. ・各種表
  23. 【改訂版環境】
  24.  ・感情表 MET
  25.  ・兆候表(戦闘時) MBOT/兆候表(非戦闘時) MNOT
  26.  ・歪み表 MDT
  27.  ・世界歪曲表 MWDT
  28.  ・永劫消失表 MEDT
  29. 【旧版環境】
  30.  ・感情表 ET/感情表 2.0 ET2
  31.  ・兆候表 OT/兆候表ver2.0 OT2/兆候表ver3.0 OT3
  32.  ・歪み表 DT/歪み表ver2.0 DT2/歪み表(野外) DTO/歪み表(海) DTS/歪み表(館・城) DTM
  33.  ・世界歪曲表 WDT/世界歪曲表2.0 WDT2
  34.  ・永劫消失表 EDT
  35. ・D66ダイスあり
  36. INFO_MESSAGE_TEXT
  37. # ダイスボットを初期化する
  38. 1 def initialize(command)
  39. 96 super(command)
  40. # 式、出目ともに送信する
  41. # D66ダイスあり(出目をソートしない)
  42. 96 @d66_sort_type = D66SortType::NO_SORT
  43. # バラバラロール(Bコマンド)でソートする
  44. 96 @sort_add_dice = true
  45. end
  46. # 固有のダイスロールコマンドを実行する
  47. # @param [String] command 入力されたコマンド
  48. # @return [String, nil] ダイスロールコマンドの実行結果
  49. 1 def eval_game_system_specific_command(command)
  50. 96 then: 39 else: 57 if (ret = check_roll(command))
  51. 39 return ret
  52. end
  53. 57 return roll_tables(command, self.class::TABLES)
  54. end
  55. 1 private
  56. 1 def check_roll(command)
  57. 96 m = /^(\d+)D6([+\-\d]*)>=(\?|\d+)(\[(\d+)?(,(\d+))?\])?$/i.match(command)
  58. 96 else: 39 then: 57 unless m
  59. 57 return nil
  60. end
  61. 39 dice_count = m[1].to_i
  62. 39 then: 39 else: 0 modify_number = m[2] ? ArithmeticEvaluator.eval(m[2]) : 0
  63. 39 target = m[3].to_i
  64. 39 then: 15 else: 24 critical = m[5]&.to_i || 12
  65. 39 then: 18 else: 21 fumble = m[7]&.to_i || 2
  66. 39 dice_list = @randomizer.roll_barabara(dice_count, 6).sort
  67. 39 dice_value = dice_list.sum()
  68. 39 dice_str = dice_list.join(",")
  69. 39 total = dice_value + modify_number
  70. result =
  71. 39 then: 15 if dice_value <= fumble
  72. 15 else: 24 Result.fumble(translate("MonotoneMuseum.automatic_failure"))
  73. 24 then: 15 elsif dice_value >= critical
  74. 15 else: 9 Result.critical(translate("MonotoneMuseum.automatic_success"))
  75. 9 then: 3 elsif target == 0
  76. 3 else: 6 Result.success(nil)
  77. 6 then: 4 elsif total >= target
  78. 4 Result.success(translate("success"))
  79. else: 2 else
  80. 2 Result.failure(translate("failure"))
  81. end
  82. sequence = [
  83. 39 "(#{command})",
  84. "#{dice_value}[#{dice_str}]#{Format.modifier(modify_number)}",
  85. total.to_s,
  86. result.text,
  87. ].compact
  88. 39 result.text = sequence.join(" > ")
  89. 39 result
  90. end
  91. # モノトーンミュージアム用のテーブル
  92. # D66を振って決定する
  93. # 1項目あたり出目2つに対応する
  94. 1 class MMTable < DiceTable::D66RangeTable
  95. # @param key [String]
  96. # @param locale [Symbol]
  97. # @return [MMTable]
  98. 1 def self.from_i18n(key, locale)
  99. 14 table = I18n.translate(key, locale: locale, raise: true)
  100. 14 new(table[:name], table[:items])
  101. end
  102. # @param name [String]
  103. # @param items [Array<String>]
  104. 1 def initialize(name, items)
  105. 14 then: 0 else: 14 if items.size != RANGE.size
  106. raise UnexpectedTableSize.new(name, items.size)
  107. end
  108. 14 items_with_range = RANGE.zip(items)
  109. 14 super(name, items_with_range)
  110. end
  111. # 1項目あたり2個
  112. 1 RANGE = [11..12, 13..14, 15..16, 21..22, 23..24, 25..26, 31..32, 33..34, 35..36, 41..42, 43..44, 45..46, 51..52, 53..54, 55..56, 61..62, 63..64, 65..66].freeze
  113. end
  114. 1 class << self
  115. 1 private
  116. 1 def translate_tables(locale)
  117. {
  118. 2 "ET" => DiceTable::D66GridTable.from_i18n("MonotoneMuseum.table.ET", locale),
  119. "ET2" => DiceTable::D66GridTable.from_i18n("MonotoneMuseum.table.ET2", locale),
  120. "OT" => DiceTable::Table.from_i18n("MonotoneMuseum.table.OT", locale),
  121. "DT" => DiceTable::Table.from_i18n("MonotoneMuseum.table.DT", locale),
  122. "DT2" => MMTable.from_i18n("MonotoneMuseum.table.DT2", locale),
  123. "WDT" => DiceTable::Table.from_i18n("MonotoneMuseum.table.WDT", locale),
  124. "WDT2" => MMTable.from_i18n("MonotoneMuseum.table.WDT2", locale),
  125. "OT2" => MMTable.from_i18n("MonotoneMuseum.table.OT2", locale),
  126. "DTO" => MMTable.from_i18n("MonotoneMuseum.table.DTO", locale),
  127. "DTS" => MMTable.from_i18n("MonotoneMuseum.table.DTS", locale),
  128. "EDT" => DiceTable::Table.from_i18n("MonotoneMuseum.table.EDT", locale),
  129. "DTM" => MMTable.from_i18n("MonotoneMuseum.table.DTM", locale),
  130. "OT3" => DiceTable::Table.from_i18n("MonotoneMuseum.table.OT3", locale),
  131. "MET" => DiceTable::D66GridTable.from_i18n("MonotoneMuseum.table.MET", locale),
  132. "MBOT" => DiceTable::Table.from_i18n("MonotoneMuseum.table.MBOT", locale),
  133. "MNOT" => DiceTable::Table.from_i18n("MonotoneMuseum.table.MNOT", locale),
  134. "MDT" => MMTable.from_i18n("MonotoneMuseum.table.MDT", locale),
  135. "MWDT" => DiceTable::Table.from_i18n("MonotoneMuseum.table.MWDT", locale),
  136. "MEDT" => DiceTable::Table.from_i18n("MonotoneMuseum.table.MEDT", locale),
  137. }
  138. end
  139. end
  140. 1 TABLES = translate_tables(:ja_jp).freeze
  141. 1 register_prefix('\d+D6', TABLES.keys)
  142. end
  143. end
  144. end

lib/bcdice/game_system/MonotoneMuseum_Korean.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/MonotoneMuseum"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class MonotoneMuseum_Korean < MonotoneMuseum
  6. # ゲームシステムの識別子
  7. 1 ID = 'MonotoneMuseum:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '모노톤 뮤지엄'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:모노톤 뮤지엄'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・판정
  15.  ・통상판정      2D6+m>=t[c,f]
  16.   수정치m,목표치t,크리티컬치c,펌블치f로 판정 굴림을 행합니다.
  17.   크리티컬, 펌블치는 생략가능합니다. ([]자체를 생략가능)
  18.   자동성공, 자동실패, 성공, 실패를 자동표기합니다.
  19. ・각종표
  20.  ・감정표 ET/감정표 2.0 ET2/개정판 감정표 MET
  21.  ・징조표 OT/징조표ver2.0 OT2/징조표ver3.0 OT3 / 개정판 전투 징조표 MBOT / 개정판 비전투 징조표 MNOT
  22.  ・일그러짐표 DT/일그러짐표ver2.0 DT2/일그러짐표(야외) DTO/일그러짐표(바다) DTS/일그러짐표(저택・성) DTM
  23.  ・세계왜곡표  WDT/세계왜곡표2.0 WDT2/개정판 왜곡표 MDT/개정판 세계왜곡표 MWDT
  24.  ・영구소실표 EDT/개정판 영구소실표 MEDT
  25. ・D66다이스 있음
  26. INFO_MESSAGE_TEXT
  27. 1 register_prefix_from_super_class()
  28. 1 def initialize(command)
  29. 43 super(command)
  30. 43 @locale = :ko_kr
  31. end
  32. 1 TABLES = translate_tables(:ko_kr).freeze
  33. end
  34. end
  35. end

lib/bcdice/game_system/NRR.rb

100.0% lines covered

92.86% branches covered

50 relevant lines. 50 lines covered and 0 lines missed.
14 total branches, 13 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class NRR < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'NRR'
  7. # ゲームシステム名
  8. 1 NAME = 'nRR'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'えぬああるあある'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGETEXT
  13. ▪️判定
  14. ・ノーマルダイス NR8
  15. ・有利ダイス NR10
  16. ・不利ダイス NR6
  17. ・Exダイス NR12
  18. ダイスの個数を指定しての判定ができます。
  19. 例:有利ダイス2個で判定 2NR10
  20. ▪️判定結果とシンボル
  21. ⭕:成功
  22. ❌:失敗
  23. ✨:クリティカル(大成功)
  24. 💀:ファンブル(大失敗)
  25. 🌈:ミラクル(奇跡)
  26. INFO_MESSAGETEXT
  27. 1 register_prefix('\d*NR(6|8|10|12)')
  28. 1 def initialize(command)
  29. 15 super(command)
  30. 15 @sort_barabara_dice = true # バラバラロール(Bコマンド)でソート有
  31. end
  32. 1 def eval_game_system_specific_command(command)
  33. 15 roll_nr(command)
  34. end
  35. 1 private
  36. 1 def roll_nr(command)
  37. 15 m = /^(\d+)?NR(6|8|10|12)$/.match(command)
  38. 15 else: 15 then: 0 return nil unless m
  39. 15 then: 2 else: 13 times = m[1]&.to_i || 1
  40. 15 table = case m[2]
  41. when: 3 when "6"
  42. 3 DISADVANTAGE
  43. when: 2 when "8"
  44. 2 NORMAL
  45. when: 2 when "10"
  46. 2 ADVANTAGE
  47. else: 8 else
  48. 8 EXTRA
  49. end
  50. 15 values = @randomizer.roll_barabara(times, table.size)
  51. 15 result = Result.new
  52. text =
  53. 15 then: 13 if times == 1
  54. 13 level = table[values[0] - 1]
  55. 13 result.condition = SUCCESSES.include?(level)
  56. 13 result.fumble = level == :fumble
  57. 13 result.critical = CRITICALS.include?(level)
  58. 13 "#{ICON[level]} #{RESULT_LABEL[level]}"
  59. else: 2 else
  60. 14 levels = values.map { |v| table[v - 1] }
  61. 2 values_count = levels
  62. .group_by(&:itself)
  63. .transform_values(&:length)
  64. 2 values_count_strs = LEVELS.map do |l|
  65. 10 count = values_count.fetch(l, 0)
  66. 10 then: 1 else: 9 next nil if count == 0
  67. 9 "#{ICON[l]} #{count}"
  68. end
  69. 2 values_count_strs.compact.join(", ")
  70. end
  71. 15 then: 13 else: 2 times_str = times == 1 ? nil : times
  72. 15 result.text = "(#{times_str}NR#{m[2]}) > #{values.join(',')} > #{text}"
  73. 15 result
  74. end
  75. 1 LEVELS = [:fumble, :failure, :success, :critical, :miracle].freeze
  76. 1 SUCCESSES = [:success, :critical, :miracle].freeze
  77. 1 CRITICALS = [:critical, :miracle].freeze
  78. 1 DISADVANTAGE = [:fumble, :failure, :failure, :failure, :success, :success].freeze
  79. 1 NORMAL = [:fumble, :failure, :failure, :failure, :success, :success, :success, :critical].freeze
  80. 1 ADVANTAGE = [:fumble, :failure, :failure, :success, :success, :success, :success, :success, :critical, :critical].freeze
  81. 1 EXTRA = [:fumble, :fumble, :failure, :failure, :success, :success, :critical, :critical, :critical, :critical, :miracle, :miracle].freeze
  82. 1 ICON = {
  83. fumble: "💀",
  84. failure: "❌",
  85. success: "⭕️",
  86. critical: "✨",
  87. miracle: "🌈",
  88. }.freeze
  89. 1 RESULT_LABEL = {
  90. fumble: "ファンブル(大失敗)",
  91. failure: "失敗",
  92. success: "成功",
  93. critical: "クリティカル(大成功)",
  94. miracle: "ミラクル(奇跡)",
  95. }.freeze
  96. end
  97. end
  98. end

lib/bcdice/game_system/NSSQ.rb

100.0% lines covered

92.86% branches covered

89 relevant lines. 89 lines covered and 0 lines missed.
42 total branches, 39 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class NSSQ < Base
  5. 1 ID = "NSSQ"
  6. 1 NAME = "SRSじゃない世界樹の迷宮TRPG"
  7. 1 SORT_KEY = "えすああるえすしやないせかいしゆのめいきゆうTRPG"
  8. 1 HELP_MESSAGE = <<~MESSAGETEXT
  9. ■ 判定 (xSQ±y>=z)
  10. xD6の判定。3つ以上振ったとき、出目の高い2つを表示します。絶対成功、絶対失敗も計算します。
  11. 2つのサイコロを使用して出目に1があった場合は、FPの獲得も表示します。3つ以上使用した場合は表示しません。
  12. ±y: yに修正値を入力。±の計算に対応。省略可能。
  13. z: 目標値。省略可能。
  14. ■ ダメージロール (xDR(C)(+)y)
  15. xD6のダメージロール。クリティカルヒットの自動判定を行います。Cを付けるとクリティカルアップ状態で計算できます。+を付けるとクリティカルヒット時のダイスが8個になります。
  16. x: xに振るダイス数を入力。
  17. y: yに耐性を入力。
  18. 例) 5DR3 5DRC4 5DRC+4
  19. ■ 回復ロール (xHRy)
  20. xD6の回復ロール。クリティカルヒットが発生しません。
  21. x: xに振るダイス数を入力。
  22. y: yに耐性を入力。省略した場合3。
  23. 例) 2HR 10HR2
  24. ■ 採集ロール (TC±z,SC±z,GC±z)
  25. 少しだけ(T)、そこそこ(S)、ガッツリ(G)採取採掘伐採を行います。
  26. z: zに追加でロールする回数を入力。省略可能。
  27. 例) TC SC+1 GC-1
  28. MESSAGETEXT
  29. 1 register_prefix('\d+SQ[\+\-\d]*', '\d+DR(C)?(\+)?\d+', '[TSG]C', '\d+HR\d*')
  30. 1 def eval_game_system_specific_command(command)
  31. 28 roll_sq(command) || damage_roll(command) || heal_roll(command) || collecting_roll(command)
  32. end
  33. 1 private
  34. # 判定
  35. 1 def roll_sq(command)
  36. 28 m = /(\d+)SQ([+\-\d]+)?(([>=]+)(\d+))?/i.match(command)
  37. 28 else: 14 then: 14 return nil unless m
  38. 14 dice_count = m[1].to_i
  39. 14 modifier = ArithmeticEvaluator.eval(m[2])
  40. 14 then: 4 else: 10 target = m[5]&.to_i
  41. 14 dice_list = @randomizer.roll_barabara(dice_count, 6)
  42. 14 largest_two = dice_list.sort.reverse.take(2)
  43. 14 total = largest_two.sum + modifier
  44. 14 num_1 = dice_list.count(1)
  45. result =
  46. 14 then: 1 if largest_two == [6, 6]
  47. 1 else: 13 Result.critical(" > 絶対成功!")
  48. 13 then: 2 elsif largest_two == [1, 1]
  49. 2 else: 11 Result.fumble(" > 絶対失敗!")
  50. 11 then: 2 elsif target && total >= target
  51. 2 else: 9 Result.success(" > 成功")
  52. 9 then: 2 elsif target && total < target
  53. 2 Result.failure(" > 失敗")
  54. else: 7 else
  55. 7 Result.new
  56. end
  57. # ダイス数が2個の場合は1の出目の数だけ【FP】を獲得できる
  58. 14 then: 4 else: 10 fp_result = dice_count == 2 && num_1 >= 1 ? " (【FP】#{num_1}獲得)" : ""
  59. sequence = [
  60. 14 "(#{command})",
  61. "[#{dice_list.join(',')}]#{Format.modifier(modifier)}",
  62. "#{total}[#{largest_two.join(',')}]#{result.text}#{fp_result}",
  63. ]
  64. 14 result.text = sequence.join(" > ")
  65. 14 return result
  66. end
  67. # ダメージロール
  68. 1 def damage_roll(command)
  69. 14 m = /(\d+)DR(C)?(\+)?(\d+)/i.match(command)
  70. 14 else: 7 then: 7 return nil unless m
  71. 7 dice_count = m[1].to_i
  72. 7 critical_up = !m[2].nil? # 強化効果 クリティカルアップ
  73. 7 increase_critical_dice = !m[3].nil?
  74. 7 resist = m[4].to_i
  75. 7 dice_list = @randomizer.roll_barabara(dice_count, 6)
  76. 7 normal_damage = damage(dice_list, resist)
  77. 7 result = "(#{command}) > [#{dice_list.join(',')}]#{resist}"
  78. 7 then: 2 else: 5 critical_target = critical_up ? 1 : 2
  79. 7 then: 4 if dice_list.count(6) - dice_list.count(1) >= critical_target
  80. 4 result += critical_damage_roll(increase_critical_dice, resist, normal_damage)
  81. 4 result = Result.critical(result)
  82. else: 3 else
  83. 3 result += " > #{normal_damage}ダメージ"
  84. 3 then: 2 else: 1 result = normal_damage > 0 ? Result.success(result) : Result.failure(result)
  85. end
  86. 7 return result
  87. end
  88. 1 def critical_damage_roll(increase_critical_dice, resist, normal_damage)
  89. 4 then: 2 else: 2 dice_count = increase_critical_dice ? 8 : 4
  90. 4 dice_list = @randomizer.roll_barabara(dice_count, 6)
  91. 4 critical_damage = damage(dice_list, resist)
  92. 4 return " > クリティカルヒット! > (#{dice_count}DR#{resist}) > [#{dice_list.join(',')}]#{resist} > #{normal_damage + critical_damage}ダメージ"
  93. end
  94. # 回復ロール
  95. 1 def heal_roll(command)
  96. 7 m = /^(\d+)HR(\d+)?$/i.match(command)
  97. 7 else: 3 then: 4 return nil unless m
  98. 3 dice_count = m[1].to_i
  99. 3 then: 1 else: 2 resist = m[2]&.to_i || 3
  100. 3 dice_list = @randomizer.roll_barabara(dice_count, 6)
  101. 3 heal_amount = damage(dice_list, resist)
  102. 3 result_text = "(#{command}) > [#{dice_list.join(',')}]#{resist} > #{heal_amount}回復"
  103. 3 then: 2 else: 1 return heal_amount > 0 ? Result.success(result_text) : Result.failure(result_text)
  104. end
  105. 1 def damage(dice_list, resist)
  106. 78 dice_list.count { |x| x > resist }
  107. end
  108. # 採取ロール
  109. 1 def collecting_roll(command)
  110. 4 m = /([TSG])C([+\-\d]+)?/i.match(command)
  111. 4 else: 4 then: 0 return nil unless m
  112. 4 type = m[1]
  113. 4 modifier = ArithmeticEvaluator.eval(m[2])
  114. aatto_param =
  115. 4 else: 0 case type
  116. when: 2 when "T"
  117. 2 3
  118. when: 1 when "S"
  119. 1 4
  120. when: 1 when "G"
  121. 1 5
  122. end
  123. 4 roll_times = aatto_param - 2 + modifier
  124. 4 then: 0 else: 4 return nil if roll_times <= 0
  125. 4 results = Array.new(roll_times) do |i|
  126. 8 dice_list = @randomizer.roll_barabara(2, 6)
  127. 8 dice = dice_list.sum()
  128. 8 "(#{command}) > #{dice}[#{dice_list.join(',')}]: #{result_collecting(i, dice, aatto_param)}"
  129. end
  130. 4 results.join("\n")
  131. end
  132. 1 def result_collecting(i, dice, aatto)
  133. 8 then: 2 if (dice <= aatto) && (aatto - 2 > i)
  134. 2 else: 6 "!ああっと!"
  135. 6 then: 2 elsif aatto - 2 <= i
  136. 2 "成功(追加分)"
  137. else: 4 else
  138. 4 "成功"
  139. end
  140. end
  141. end
  142. end
  143. end

lib/bcdice/game_system/Nechronica.rb

100.0% lines covered

95.45% branches covered

65 relevant lines. 65 lines covered and 0 lines missed.
22 total branches, 21 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/dice_table/table'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Nechronica < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'Nechronica'
  8. # ゲームシステム名
  9. 1 NAME = 'ネクロニカ'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'ねくろにか'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・判定 (nNC+m)
  15.  ダイス数n、修正値mで判定ロールを行います(省略=1)
  16.  ダイス数が2以上の時のパーツ破損数も表示します。
  17. ・攻撃判定 (nNA+m)
  18.  ダイス数n、修正値mで攻撃判定ロールを行います(省略=1)
  19.  命中部位とダイス数が2以上の時のパーツ破損数も表示します。
  20. ・姉妹への未練表 nm
  21. ・中立者への未練表 nmn
  22. ・敵への未練表 nme
  23. INFO_MESSAGE_TEXT
  24. 1 def initialize(command)
  25. 65 super(command)
  26. 65 @sort_add_dice = true
  27. 65 @sort_barabara_dice = true
  28. 65 @default_target_number = 6 # 目標値が空欄の時の目標値
  29. end
  30. 1 def eval_game_system_specific_command(command)
  31. 57 roll_tables(command, self.class::TABLES) || nechronica_check(command)
  32. end
  33. 1 def result_nd10(total, _dice_total, value_list, cmp_op, target)
  34. # 後方互換を維持するため、1d10>=nを目標値nの1NCとして処理
  35. 8 then: 3 else: 5 if value_list.count != 1 || cmp_op != :>= || target.nil? || target == "?"
  36. 3 return nil
  37. end
  38. 5 result_nechronica([total], target)
  39. end
  40. 1 private
  41. 1 def result_nechronica(value_list, target)
  42. 50 then: 32 if value_list.max >= target
  43. 32 then: 11 if value_list.max >= 11
  44. 11 Result.critical(translate("Nechronica.critical"))
  45. else: 21 else
  46. 21 Result.success(translate("success"))
  47. else: 18 end
  48. 44 then: 8 elsif value_list.count { |i| i <= 1 } == 0
  49. 8 else: 10 Result.failure(translate("failure"))
  50. 10 then: 4 elsif value_list.size > 1
  51. 4 break_all_parts = translate("Nechronica.break_all_parts")
  52. 4 fumble = translate("Nechronica.fumble")
  53. 4 Result.fumble("#{fumble} > #{break_all_parts}")
  54. else: 6 else
  55. 6 Result.fumble(translate("Nechronica.fumble"))
  56. end
  57. end
  58. # Rコマンドの後方互換を維持する
  59. 1 def r_backward_compatibility(command)
  60. 45 m = command.match(/^(\d)?R10([+\-\d]+)?(\[(\d+)\])?$/)
  61. 45 else: 3 then: 42 return command unless m
  62. 3 then: 2 if m[4] == "1"
  63. 2 "#{m[1]}NA#{m[2]}"
  64. else: 1 else
  65. 1 "#{m[1]}NC#{m[2]}"
  66. end
  67. end
  68. 1 def nechronica_check(command)
  69. 45 command = r_backward_compatibility(command)
  70. # 歴史的経緯で10を受理する
  71. 45 cmd = Command::Parser.new(/N[CA](10)?/, round_type: round_type)
  72. .enable_prefix_number.parse(command)
  73. 45 else: 45 then: 0 return nil unless cmd
  74. 45 dice_count = [1, cmd.prefix_number.to_i].max
  75. 45 modify_number = cmd.modify_number || 0
  76. 45 dice = @randomizer.roll_barabara(dice_count, 10).sort
  77. 133 dice_mod = dice.map { |i| i + modify_number }
  78. 45 total = dice_mod.max
  79. 45 then: 20 else: 25 na = get_hit_location(total) if cmd.command.start_with?("NA")
  80. 45 result = result_nechronica(dice_mod, 6)
  81. sequence = [
  82. 45 "(#{cmd})",
  83. "[#{dice.join(',')}]#{Format.modifier(modify_number)}",
  84. "#{total}[#{dice_mod.join(',')}]",
  85. result.text,
  86. na,
  87. ].compact
  88. 45 result.text = sequence.join(" > ")
  89. 45 return result
  90. end
  91. 1 def get_hit_location(value)
  92. 20 then: 8 else: 12 return nil if value <= 5
  93. 12 table = translate("Nechronica.hit_location.table")
  94. 12 text = table[(value - 6).clamp(0, 5)]
  95. 12 then: 4 if value > 10
  96. 4 text + translate("Nechronica.hit_location.additional_damage", damage: value - 10)
  97. else: 8 else
  98. 8 text
  99. end
  100. end
  101. 1 class << self
  102. 1 private
  103. 1 def translate_tables(locale)
  104. {
  105. 2 "NM" => DiceTable::Table.from_i18n("Nechronica.table.NM", locale),
  106. "NMN" => DiceTable::Table.from_i18n("Nechronica.table.NMN", locale),
  107. "NME" => DiceTable::Table.from_i18n("Nechronica.table.NME", locale),
  108. }
  109. end
  110. end
  111. 1 TABLES = translate_tables(:ja_jp)
  112. 1 register_prefix('\d?NC', '\d?NA', '\dR10', TABLES.keys)
  113. end
  114. end
  115. end

lib/bcdice/game_system/Nechronica_Korean.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/Nechronica"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Nechronica_Korean < Nechronica
  6. # ゲームシステムの識別子
  7. 1 ID = 'Nechronica:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '네크로니카'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:네크로니카'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・판정 (nNC+m)
  15.  주사위 수n, 수정치m으로 판정굴림을 행합니다.
  16.  주사위 수가 2개 이상일 때에 파츠파손 수도 표시합니다.
  17. ・공격판정 (nNA+m)
  18.  주사위 수n, 수정치m으로 공격판정굴림을 행합니다.
  19.  명중부위와 주사위 수가 2개 이상일 때에 파츠파손 수도 표시합니다.
  20. ・자매에 대한 미련표 nm
  21. ・중립자에 대한 미련표 nmn
  22. ・적에 대한 미련표 nme
  23. INFO_MESSAGE_TEXT
  24. 1 register_prefix_from_super_class()
  25. 1 def initialize(command)
  26. 28 super(command)
  27. 28 @locale = :ko_kr
  28. end
  29. 1 TABLES = translate_tables(:ko_kr)
  30. end
  31. end
  32. end

lib/bcdice/game_system/NervWhitePaper.rb

100.0% lines covered

93.33% branches covered

72 relevant lines. 72 lines covered and 0 lines missed.
30 total branches, 28 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class NervWhitePaper < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'NervWhitePaper'
  7. # ゲームシステム名
  8. 1 NAME = '新世紀エヴァンゲリオンRPG NERV白書/使徒降臨'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'しんせいきえうあんけりおんああるひいしいねるふはくしよしとこおりん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGETEXT
  13. ■通常ロール(NR):成功、失敗、絶対成功、絶対失敗を表示します。
  14. 例) NR
  15. ■長所ロール(NA):成功、失敗、絶対成功、絶対失敗を表示します。
  16. 例) NA
  17. ■短所ロール(ND):成功、失敗、絶対成功、絶対失敗を表示します。
  18. 例) ND
  19. INFO_MESSAGETEXT
  20. 1 register_prefix('N[RAD]')
  21. 1 def eval_game_system_specific_command(command)
  22. 14 resolute_regular_action(command) ||
  23. resolute_advantage_action(command) ||
  24. resolute_disadvantage_action(command)
  25. end
  26. 1 private
  27. # 通常ロールによる判定
  28. # @param [String] command
  29. # @return [Result]
  30. 1 def resolute_regular_action(command)
  31. 14 m = /NR/.match(command)
  32. 14 else: 5 then: 9 return nil unless m
  33. 5 dices = @randomizer.roll_barabara(2, 6)
  34. 5 dice_text = dices.join(",")
  35. 5 dice_add = dices.sum
  36. 5 output = "(NR) > #{dice_text}"
  37. 5 then: 1 if dice_add == 7
  38. 1 output += " > 絶対成功"
  39. 1 else: 4 return Result.critical(output)
  40. 4 then: 1 elsif dice_add == 2
  41. 1 output += " > 絶対失敗"
  42. 1 else: 3 return Result.fumble(output)
  43. 3 then: 1 elsif dice_add == 12
  44. 1 output += " > 絶対失敗"
  45. 1 else: 2 return Result.fumble(output)
  46. 2 then: 1 elsif dice_add.modulo(2) == 0
  47. 1 output += " > 失敗"
  48. 1 return Result.failure(output)
  49. else: 1 else
  50. 1 output += " > 成功"
  51. 1 return Result.success(output)
  52. end
  53. end
  54. # 長所ロールによる判定
  55. # @param [String] command
  56. # @return [Result]
  57. 1 def resolute_advantage_action(command)
  58. 9 m = /NA/.match(command)
  59. 9 else: 5 then: 4 return nil unless m
  60. 5 dices = @randomizer.roll_barabara(2, 6)
  61. 5 dice_text = dices.join(",")
  62. 5 dice_add = dices.sum
  63. 5 output = "(NA) > #{dice_text}"
  64. 5 then: 1 if dice_add == 7
  65. 1 output += " > 絶対成功"
  66. 1 else: 4 return Result.critical(output)
  67. 4 then: 1 elsif dice_add == 2
  68. 1 output += " > 絶対失敗"
  69. 1 else: 3 return Result.fumble(output)
  70. 3 then: 1 elsif dice_add == 12
  71. 1 output += " > 絶対失敗"
  72. 1 else: 2 return Result.fumble(output)
  73. 2 then: 1 elsif dices[0] == dices[1]
  74. 1 output += " > 失敗"
  75. 1 return Result.failure(output)
  76. else: 1 else
  77. 1 output += " > 成功"
  78. 1 return Result.success(output)
  79. end
  80. end
  81. # 短所ロールによる判定
  82. # @param [String] command
  83. # @return [Result]
  84. 1 def resolute_disadvantage_action(command)
  85. 4 m = /ND/.match(command)
  86. 4 else: 4 then: 0 return nil unless m
  87. 4 dices = @randomizer.roll_barabara(2, 6)
  88. 4 dice_text = dices.join(",")
  89. 4 dice_add = dices.sum
  90. 4 output = "(ND) > #{dice_text}"
  91. 4 then: 1 if dice_add == 7
  92. 1 output += " > 絶対成功"
  93. 1 else: 3 return Result.critical(output)
  94. 3 then: 1 elsif dice_add == 2
  95. 1 output += " > 絶対失敗"
  96. 1 else: 2 return Result.fumble(output)
  97. 2 then: 1 elsif dice_add == 12
  98. 1 output += " > 絶対失敗"
  99. 1 else: 1 return Result.fumble(output)
  100. 1 then: 1 else: 0 elsif dice_add != 7
  101. 1 output += " > 失敗"
  102. 1 return Result.failure(output)
  103. end
  104. end
  105. end
  106. end
  107. end

lib/bcdice/game_system/NeverCloud.rb

97.73% lines covered

95.0% branches covered

44 relevant lines. 43 lines covered and 1 lines missed.
20 total branches, 19 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/dice_table/table"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class NeverCloud < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'NeverCloud'
  8. # ゲームシステム名
  9. 1 NAME = 'ネバークラウドTRPG'
  10. # ゲームシステム名の読みがな
  11. #
  12. # 「ゲームシステム名の読みがなの設定方法」(docs/dicebot_sort_key.md)を参考にして
  13. # 設定してください
  14. 1 SORT_KEY = 'ねはあくらうとTRPG'
  15. # ダイスボットの使い方
  16. 1 HELP_MESSAGE = <<~MESSAGETEXT
  17. ・LIST のコマンドを入力して、ルールの解説・2D6表、一覧の表示
  18. ・判定(xNC±y>=z)
  19.  xD6の判定を行います。ファンブル、クリティカルの場合、その旨を出力します。
  20.  x:振るダイスの数。
  21.  ±y:固定値・修正値。省略可能。
  22.  z:目標値。省略可能。
  23.  ダイスの出目ふたつが6ならクリティカル(自動成功)
  24.  ダイスの出目すべてが1ならファンブル(自動失敗)
  25.  例) 2NC+2>=5 1NC
  26. MESSAGETEXT
  27. 1 def eval_game_system_specific_command(command)
  28. 103 then: 94 if /^(\d+)(?:NC|D6?)((?:[-+]\d+)*)(>=(\d+))?$/i.match?(command)
  29. 94 else: 9 return check_action(command)
  30. 9 then: 3 elsif TEXTS.key?(command)
  31. 3 else: 6 return TEXTS[command].chomp
  32. 6 then: 5 elsif TABLES.key?(command)
  33. 5 else: 1 return roll_tables(command, TABLES)
  34. 1 then: 1 elsif ALIAS_TEXTS.key?(command)
  35. 1 return TEXTS[ALIAS_TEXTS[command]].chomp
  36. else: 0 else
  37. return nil
  38. end
  39. end
  40. 1 def check_action(command)
  41. 94 m = /^(\d+)(?:NC|D6?)((?:[-+]\d+)*)(>=(\d+))?$/i.match(command)
  42. 94 dice_count = m[1].to_i
  43. 94 modify_str = m[2]
  44. 94 modify_number = ArithmeticEvaluator.eval(modify_str)
  45. 94 cmp_str = m[3]
  46. 94 then: 82 else: 12 target = m[4]&.to_i
  47. 94 then: 36 else: 58 if modify_number == 0
  48. 36 modify_str = ''
  49. end
  50. 94 dice_list = @randomizer.roll_barabara(dice_count, 6)
  51. 94 dice_value = dice_list.sum()
  52. 94 dice_str = dice_list.join(",")
  53. 94 total = dice_value + modify_number
  54. result =
  55. 94 then: 20 if dice_list.count(1) == dice_count
  56. 20 total = 0
  57. 20 else: 74 "ファンブル"
  58. 74 then: 19 elsif dice_list.count(6) >= 2
  59. 19 else: 55 "クリティカル"
  60. 55 then: 49 else: 6 elsif target
  61. 49 then: 33 else: 16 total >= target ? "成功" : "失敗"
  62. end
  63. sequence = [
  64. 94 "(#{dice_count}D6#{modify_str}#{cmp_str})",
  65. "#{dice_value}[#{dice_str}]#{modify_str}",
  66. total,
  67. result
  68. ].compact
  69. 94 return sequence.join(" > ")
  70. end
  71. 1 TEXTS = {
  72. 'LIST' => <<~TEXT,
  73. ※注記:このダイスボットデータは『ネバークラウドTRPG』公式『私立彩音学園』主導の下で制作されました。
  74. ・公式サイト:https://sion-academy.wixsite.com/nctrpg
  75. ・公式リプレイ:https://sion-academy.wixsite.com/nctrpg-kaleido
  76. ・キャラ作成アプリ:https://nctrpg.com/bloomi
  77. ・判定(xD6±y>=z)
  78. ()内のコマンドを入力して詳細を表示。
  79. 2D6(CHAR1) ・所属表(2D6またはRoC。基本ルール書籍版P33)
  80. 2D6(CHAR2) ・趣味表(2D6またはRoC。基本ルール書籍版P38)
  81. 2D6(CHAR3) ・リビド武装形状表(2D6またはRoC。基本ルール書籍版P39)
  82. 2D6(NAYA1) 悩みの詳細表・愛/Love:得意方向(正面)(2D6またはRoC。基本ルール書籍版P49)
  83. 2D6(NAYA2) 悩みの詳細表・体/Figure:得意方向(正面)(2D6またはRoC。基本ルール書籍版P49)
  84. 2D6(NAYA3) 悩みの詳細表・才/Talent:得意方向(背面)(2D6またはRoC。基本ルール書籍版P49)
  85. 2D6(NAYA4) 悩みの詳細表・絆/Bonds:得意方向(側面)(2D6またはRoC。基本ルール書籍版P49)
  86. 2D6(NAYA5) 悩みの詳細表・住/Home:得意方向(側面)(2D6またはRoC。基本ルール書籍版P49)
  87. 各種2D6:RoC表はコマンドの最後にアルファベットのLを付けて一覧表示が可能(例:NAYA5→NAYA5L)
  88. (LIKE1) LIKE(基本ルール書籍版P60)
  89. (RESE1) リサーチカード(基本ルール書籍版P63)
  90. (RESE2) インタビュー(基本ルール書籍版P62)
  91. (RESE3) パイルドライヴ(基本ルール書籍版P64)
  92. (RESE4) [決意]と[使命](基本ルール書籍版P61)
  93. (ARTS1) リビドアーツのデータ項目(基本ルール書籍版P40)
  94. (STAT1) SSリスト(基本ルール書籍版P41)
  95. (STAT2) LSリスト(基本ルール書籍版P411)
  96. (ACTI1) タイミング:サブアクション(基本ルール書籍版P422)
  97. (ACTI2) タイミング:メインアクション(基本ルール書籍版P42)
  98. (ACTI3) タイミング:インスタント(基本ルール書籍版P42)
  99. (ACTI4) サーヴァント共通アクション(基本ルール書籍版P42)
  100. (BATT1) ラストパイル(基本ルール書籍版P67)
  101. (BATT2) 攻撃の手順(メインアクションで行う)01.攻撃宣言ステップ(基本ルール書籍版P74)
  102. (BATT3) 攻撃の手順(メインアクションで行う)02.命中判定ステップ(基本ルール書籍版P74)
  103. (BATT4) 攻撃の手順(メインアクションで行う)03.ダメージ決定ステップ(基本ルール書籍版P74)
  104. (BATT5) 攻撃の手順(メインアクションで行う)04.ダメージ適用ステップ(基本ルール書籍版P74)
  105. (BATT6) [決意]の効果(基本ルール書籍版P61)
  106. (BATT7) [使命]の効果(基本ルール書籍版P61)
  107. (BATT8) パケット(基本ルール書籍版P69)
  108. (BATT9) リビドストーム(基本ルール書籍版P71)
  109. (PIET1) ピーターの基本的な性質(基本ルール書籍版P72)
  110. (PIET2) 《AoE》(Area_of_Effect)(基本ルール書籍版P72)
  111. (PIET3) ピーターの「行動指針」((2D6またはRoC。基本ルール書籍版P110)
  112. (MINI1) 基本ルールからねばくらミニへの変更点(ねばくらミニ書籍版P05)
  113. (MINI2) ねばくらミニでのリサーチのルール変更点(ねばくらミニ書籍版P11)
  114. (MINI3) ねばくらミニでのバトル演出のルール(ねばくらミニ書籍版P12)
  115. (MINI4) ねばくらミニでのアーツ(ねばくらミニ書籍版P13)
  116. (MINI5) ねばくらミニでのスペシャルアーツ(ねばくらミニ書籍版P13)
  117. (MINI6) ねばくらミニでのポータルとサーヴァント(ねばくらミニ書籍版P14)
  118. TEXT
  119. 'LIKE1' => <<~TEXT,
  120. LIKE(基本ルール書籍版P60)
  121. ・全ての参加者(PLやGMや見学者)はセッション中にPCやGMのロールプレイや行動に、
  122.  共感や称賛や琴線に触れた時[LIKE:~]と言ってその内容と共に記述して蓄積して行く。
  123. ・リサーチ中では手番を消費せず[LIKE]1点ごとに対象の{HP}を[50]点回復させても良い。
  124. TEXT
  125. 'RESE1' => <<~TEXT,
  126. リサーチカード(基本ルール書籍版P63)
  127. ・リサーチ中に捜査対象とされるもの。オモテ面に「名称」「難易度」「ピーターのバフ」「情景描写」が記述される。
  128. ・「ウラ面」には[Pコトノハ]「暴露描写」が記述される。「暴露描写」を閲覧したロールプレイは主に[LIKE]の創出に寄与する。
  129. ・リサーチカードの選択とWコトノハと使用能力値の提示→PCのロールプレイ→判定が成功の場合→GMから暴露描写の提示→PCのロールプレイ。
  130. TEXT
  131. 'RESE2' => <<~TEXT,
  132. インタビュー(基本ルール書籍版P62)
  133. ・自分以外のPC1人の「悩みの詳細」「追加設定」または〈パイルドライヴ〉済みの暴露描写1つを対象とし、
  134.  その内容を拡張するような質問をする。対象となったPCまたはGMは「追加設定」を作成して公開する。
  135. ・質問者は「追加設定」から単語かフレーズ1つを切り出し[ワード]として記録する。
  136. ・これらの「追加設定」やロールプレイは主に[LIKE]の創出に寄与される。
  137. TEXT
  138. 'RESE3' => <<~TEXT,
  139. パイルドライヴ(基本ルール書籍版P64)
  140. ・調査判定時にプリプレイで選択した[Wコトノハ]と「ウラ面」の[Pコトノハ]が同一ならば、
  141.  自動成功(レゾナンス・パイルドライヴ)として、PCは[30]のHPダメージを受け「ウラ面」を開示する。
  142. ・[Pコトノハ]が合っておらずとも「[RW能力値/知識/コミュ力/趣味]+2D」の判定で
  143. 「難易度」以上ならば成功(パイルドライヴ)として、PCは[30]のHPダメージを受け「ウラ面」を開示し[Pコトノハ]を手に入れる。
  144. ・指定されたサイクル以内に「ウラ面」を開示できなかった、
  145.  リサーチカードの「ピーターのバフ」は戦闘シーンの〈ピーター〉に付与される。
  146. TEXT
  147. 'RESE4' => <<~TEXT,
  148. [決意]と[使命](基本ルール書籍版P61)
  149. ・リサーチ終了時に[LIKE]を[決意]という戦闘時に使用する単位に変換する。
  150. ・この時[LIKE]が50個以上の場合、GMは[決意]を無制限に使用することにしても良い。
  151. ・これとは別にGMは[LIKE]の合計点を5で割った値を[使命]言う単位(最大5点)とする。
  152.  [決意]と[使命]は[Pコトノハ][Sコトノハ][ワード]の単語ごとに割り振られ、これらの単語を使用したロールプレイを推奨する。
  153. TEXT
  154. 'ARTS1' => <<~TEXT,
  155. リビドアーツのデータ項目(基本ルール書籍版P40)
  156. ・射程:起点から『ぴったり』に、何Sq離れたキャラクターを対象に取れるかを示す。射程0は自身のみのことである。
  157. ・威力:そのアーツを使用した結果に対象に及ぼす数値を示す。ダイスロールを含む場合「威力ロール」と呼ぶ。
  158. ・コスト/制限:コストとして実行者の{パケット}をn点上昇させる。
  159. ・スペシャルアーツ:「タイミング:インスタント」必ず[決意]1点を消費する。この時「[決意]の効果」は発生しない。
  160. ・アーツのリネーム:取得アーツはPCの設定に合わせ(他のアーツと誤解させないよう)名前を好きに変更しても良い。
  161. TEXT
  162. 'STAT1' => <<~TEXT,
  163. SSリスト(基本ルール書籍版P41)
  164.  下記4つのショートステータス(SS)は準備プロセス終了時に解除される。
  165. ・[SS感覚障害] 全ての判定に-1D&{技量}が0になる(判定時のダイス目の1はファンブルになる)
  166. ・[SS混乱] 行動前に1Dを振り偶数だった場合は行動できない。
  167. ・[SS危機] 回避判定を行えず「致命的命中(ダメージ2倍)になる。
  168. ・[SSマーク] 「{パケット}の値が最も高いPC、[レッド]として扱う。
  169. TEXT
  170. 'STAT2' => <<~TEXT,
  171. LSリスト(基本ルール書籍版P41)
  172.  下記4つのロングステータス(LS)は準備プロセス終了時に解除されない。
  173. ・[リフレクト] ダメージを受けた時その2倍の値のダメージを相手に与え効果を解除する。
  174. ・[ブースト:n] [威力ロール]の前に消費を選択した場合は威力ロールに[+n]を与え効果を解除する。
  175. ・[DoT:xTn](Damage_on_Time) 準備プロセスにx点のHPダメージを受け、
  176.  nを1減らし0になると解除される。効果が累積した場合それぞれ大きい値になる。
  177. ・[行動不能] HPが0になった時[未行動]でなくなり、全ての行動や判定を行うことができない。
  178.  {パケット}が0になり全てのSSが解除される。《助け起こす》または[フレンドシップ]1つ消費して[未行動]になることで解除できる。
  179. TEXT
  180. 'ACTI1' => <<~TEXT,
  181. タイミング:サブアクション(基本ルール書籍版P42)
  182. ・《通常移動》{移動力}Sq数まで自分のコマを動かす。
  183. ・《全力移動》{移動力}+2Sq数まで自分のコマを動かす。メインアクションを行う権利を失う。
  184. TEXT
  185. 'ACTI2' => <<~TEXT,
  186. タイミング:メインアクション(基本ルール書籍版P42)
  187. ・《かばう》射程0~2。次に対象が受けるダメージを1回だけ肩代わりする。
  188. ・《武装解除》即座にそのバトルシーンから退場する。そのシーンに復帰することができない。
  189. ・《助け起こす》射程:1。他のPCの[行動不能]を解除し{HP}を1まで回復する。
  190. TEXT
  191. 'ACTI3' => <<~TEXT,
  192. タイミング:インスタント(基本ルール書籍版P42)
  193.  (行動権プロセスに使用する。1回のタイミングに行動は1回まで)
  194. ・《シフト》制限:シーン1回。即座に2Sqまで移動できる。
  195. ・《ギミック解除》射程1。制限:サイクル1回。「要求能力値」があるギミックに判定を行い[達成値]8以上だった場合これを除外する。
  196. ・《クイックロード》制限:シーン1回。バトルシーン最初の行動権プロセスでのみ使用できる。使用者の{パケット}を+3する。
  197. TEXT
  198. 'ACTI4' => <<~TEXT,
  199. サーヴァント共通アクション(基本ルール書籍版P42)
  200. ・《リバース》タイミング:インスタントまたは戦闘開始時。射程:1。サーヴァントコマが無い場合新たに設置し{HP}10を譲り渡す。
  201. ・《相互移動》タイミング:サブアクション。サーヴァントと自身を合計4Sqまで移動できる。
  202. ・《複数視点》タイミング:インスタント。制限:サイクル1回&サーヴァントと分離中のみ。次の回避判定に+2の修正を得る。
  203. TEXT
  204. 'BATT1' => <<~TEXT,
  205. ラストパイル(基本ルール書籍版P67)
  206.  各PCはそれまでに集まった[決意]や「ワード」から使いたい言葉を含んだロールプレイによって
  207. 「戦う理由」を宣言すること。行わなければ次のバトルシーンのエンカウントシート上に登場することができない。
  208. TEXT
  209. 'BATT2' => <<~TEXT,
  210. 攻撃の手順(メインアクションで行う)01.攻撃宣言ステップ(基本ルール書籍版P74)
  211. ・攻撃側は攻撃に用いる行動と対象とコスト/制限の宣言を行う。
  212. ・GMが対象が適切であることを確認し(適切でないなら巻き戻す)をコスト/制限の支払いを確認する。
  213. ・攻撃側が〈ピーター〉なら、攻撃の対象に{正面}を向ける(向きを変えるのはこの場面のみ)
  214. TEXT
  215. 'BATT3' => <<~TEXT,
  216. 攻撃の手順(メインアクションで行う)02.命中判定ステップ(基本ルール書籍版P74)
  217. 「判定」が「自動成功」「受動任意」の場合「命中」したとして、ダメージ決定ステップに移る。
  218. ・攻撃側は[命中値](=行動による固定値+{技量}+「ポータル」による修正値)を宣言する。
  219. ・防御側は[回避値](=2D6の値)を宣言する。
  220. ・攻撃側の1ゾロまたは防御側が6ゾロの場合「全回避」として、攻撃の終了に移る。
  221. ・[命中値]≦[回避値]の場合「半回避」になる。
  222. ・[命中値]>[回避値]の場合「命中」になる。
  223. ・防御側が1ゾロの場合「致命的命中」として、03.ダメージ決定ステップに移る。
  224. TEXT
  225. 'BATT4' => <<~TEXT,
  226. 攻撃の手順(メインアクションで行う)03.ダメージ決定ステップ(基本ルール書籍版P74)
  227.  この手順は決して巻き戻さず下記の順で累積させて、04.ダメージ適用ステップに移る。
  228. ・攻撃側は[ブースト]を使用するか決定する。
  229. ・攻撃側は次に[威力ロール]を使うダメージを算出する。
  230. ・攻撃側は最後に[威力ロール]を使わない(特殊効果による)ダメージを算出する。
  231. TEXT
  232. 'BATT5' => <<~TEXT,
  233. 攻撃の手順(メインアクションで行う)04.ダメージ適用ステップ(基本ルール書籍版P74)
  234. ・攻撃側が「{得意方向}以外への攻撃」または「半回避」の場合、HPダメージ半減(切り捨て)+SS無効(DoTは数値共に半減)
  235. ・攻撃側が「{得意方向}以外への攻撃」かつ「半回避」の場合、2つの半減効果は累積しない。
  236. ・回避側が「致命的命中」の場合、HPダメージ2倍にする。
  237. ・攻撃側が「{得意方向}以外への攻撃」かつ回避側が「致命的命中」の場合、半減効果かつ2倍ダメージで元の数値に中和される。
  238. ・以上のHPダメージを防御側の{HP}から引く。
  239. ・防御側の{パケット}を1減らす。この時[リフレクト]をもっていた場合その2倍のHPダメージを攻撃側に与える。
  240. ・最後に「{得意方向}への攻撃」だった場合、攻撃側は[SS危機]を受ける。
  241. TEXT
  242. 'BATT6' => <<~TEXT,
  243. [決意]の効果(基本ルール書籍版P61)
  244. ・〈ピーター〉の{アーツ}を1つ、または{HP}残量、または{行動指針}を公開させる。
  245. ・直前のPCまたは〈ピーター〉の判定を1回だけ振り直させる。
  246. ・行動権プロセスでPCの誰か1人の[SS危機]1つを即座に解除する。
  247. TEXT
  248. 'BATT7' => <<~TEXT,
  249. [使命]の効果(基本ルール書籍版P61)
  250. ・行動権プロセスで〈ピーター〉のSS1つを解除する。
  251. ・行動権プロセスで〈ピーター〉の向きを90度変える(制限:サイクル中2回)
  252. ・行動権プロセスで[未行動]のPC1人を[レッド]にする(制限:シーン中1回)
  253. ・次の〈ピーター〉の手番で全PCの{パケット}が0とする(攻撃対象の基準が行動指針になる)(制限:シーン中1回)
  254. TEXT
  255. 'BATT8' => <<~TEXT,
  256. パケット(基本ルール書籍版P69)
  257.  {パケット}に上限は無く最低値は0である。戦闘開始時と戦闘終了時に各PCの{パケット}を0にする。
  258.  {リビドアーツ}の使用時にコストとして上昇し、ダメージを受けたPCはダメージ適用ステップで「{パケット}を-1」する。
  259.  サーヴァントの{パケット}は自らのPCと同じくする。
  260. TEXT
  261. 'BATT9' => <<~TEXT,
  262. リビドストーム(基本ルール書籍版P71)
  263. 〈ピーター〉のナナメにあるSqを【リビドストーム】と呼ぶ。
  264.  このSqにいるキャラクターは攻撃の際に自身の{得意方向}の効果が無効になる。
  265. TEXT
  266. 'PIET1' => <<~TEXT,
  267. ピーターの基本的な性質(基本ルール書籍版P72)
  268. ・《AoE》(Area_of_Effect)を持つ。{リビドタイプ}と{属性}と{得意方向}と{パケット}を持たず、移動しない。
  269. ・〈ピーター〉が攻撃対象を選択する場合、特別な記載が無い限り「{パケット}の値が最も高い[レッド]」のPCを優先的に選択し
  270. 「向き」を変えて攻撃する(向きを変えるのはこの場面のみ)[レッド]が複数いる場合その中で[SS危機]を持つPCを特に優先する。
  271.  さらに対象が複数いる場合「行動指針」の影響を受ける。
  272. 「行動指針」のリストの上下端に近いものほど処理が複雑化したり、PCの行動を制限するため推奨されない。
  273. TEXT
  274. 'PIET2' => <<~TEXT,
  275. 《AoE》(Area_of_Effect)(基本ルール書籍版P72)
  276.  選択したAoEエリア_命中:自動成功_威力:50+(10×{PR})
  277.  サイクル開始時に効果範囲を設置、終了時に起動して効果範囲内のPCにダメージを与える。
  278.  サイクル開始時に効果範囲内であっても起動時までに範囲外であればダメージは受けない。
  279. TEXT
  280. 'PIET3' => <<~TEXT,
  281. ピーターの「行動指針」((2D6またはRoC。基本ルール書籍版P110)
  282. 02:ストーカー : 戦闘開始時にPCを1人指定し、そのPCを標的にする。
  283. 03:強敵狙い : 現在のサイクルで最も高い威力ロールを行ったPCを標的にする。
  284. 04:近距離狙い : このエネミーに最も近いPCを標的にする。
  285. 05:マウンティング : このエネミーよりも行動力の低いPCを標的にする。
  286. 06:同族狙い : 〈ターゲット〉と同じ属性のPCを標的にする。
  287. 07:遠距離狙い : このエネミーから最も遠いPCを標的にする。
  288. 08:ハンター : SSを所持しているPCを標的にする。
  289. 09:とどめ打ち : {HP}が最大値の4分の1以下のPCを標的にする。
  290. 10:臆病者狙い : 現在のサイクルでピーターから距離をとったPCを標的にする。
  291. 11:特定属性狙い : 戦闘開始時に指定した属性のPCを標的にする。
  292. 12:天の邪鬼 : [SS危機]を持たないPCを標的とし、持つPCは優先しなくなる。
  293. TEXT
  294. 'MINI1' => <<~TEXT,
  295. 基本ルールからねばくらミニへの変更点(ねばくらミニ書籍版P05)
  296. ・PLは3人(推定4時間)とする。人数を増やすのは構わないが所要時間を4人(5時間半)、5人(7時間半)とする。
  297. ・リサーチフェイズは戦闘も含めたクエストフェイズと呼び替える。バトルフェイズは存在しない。
  298. ・オープニングフェイズ、エンディングフェイズは1シーンのみとする。
  299. ・クエストフェイズは導入のシーンと、捜査・宣戦布告・戦闘の演出(総計3サイクル)のクエストシーンによって構成される。
  300.  1つの手番の(テキストセッションの)所要時間の目安は10分ほど。
  301.  ラストパイルも、インタビューも、1人あたり1回10分の持ち時間を想定している。
  302. TEXT
  303. 'MINI2' => <<~TEXT,
  304. ねばくらミニでのリサーチのルール変更点(ねばくらミニ書籍版P11)
  305. ・[Wコトノハ]は宣言せず〈レゾナンス・パイルドライヴ〉は発生しない(プリプレイでも[Wコトノハ]を選択しない)
  306. ・「ピーターのバフ」は無効になる。
  307. ・《インタビュー》はPCごとにシーン1回10分とする。
  308. TEXT
  309. 'MINI3' => <<~TEXT,
  310. ねばくらミニでのバトル演出のルール(ねばくらミニ書籍版P12)
  311. ・エンカウントシート(移動・射程・方角・方向・AoEのルール)を使用せず「サイクル制限:1サイクル」で行う。
  312. ・バトル演出中に全PCが出したHPダメージの値を累積して「ダメージ合計」に加算しサイクル終了時に「勝利値」以上であれば勝利する。
  313. ・勝利値:[300+「ウラ返しにされなかったリサーチカードの枚数」×50]
  314. ・PLが4人以上び場合、勝利値に[(人数-3)×100]をさらに加えてもよい。
  315. TEXT
  316. 'MINI4' => <<~TEXT,
  317. ねばくらミニでのアーツ(ねばくらミニ書籍版P13)
  318. ・攻撃アーツ:アーツの効果がそのまま適用される。HPダメージを「ダメージ合計」に加える。
  319. ・DoTの選択ルール:使用者が望む場合(防御判定よりも前に宣言すること)
  320.  対象に適用された[DoT:xTn]を、[xかけるn÷2]のHPダメージとして扱う(対象が半回避した場合xとnの両方が半減する)
  321. ・支援アーツ:対象が次に与えるHPダメージを倍にする(名前の違うアーツによるものであっても効果は累積しない)
  322. 《リフレクト》上記の支援アーツの効果のかわりに、元の効果文のとおりに対象に[リフレクト]を与えてもよい。
  323. ・支援アーツ:対象が次に受けるHPダメージを倍にする(名前の違うアーツによるものであっても効果は累積しない)
  324. TEXT
  325. 'MINI5' => <<~TEXT,
  326. ねばくらミニでのスペシャルアーツ(ねばくらミニ書籍版P13)
  327. ・コストとして[決意]を消費し1度はRPをする必要がある。
  328. ・対象がPCなら、対象が次に与えるHPダメージを倍にする。他の「与えるHPダメージを倍にする」効果に累積する。
  329. ・対象がエネミーなら、対象が次に受けるHPダメージを倍にする。他の「受けるHPダメージを倍にする」効果に累積する。
  330. TEXT
  331. 'MINI6' => <<~TEXT,
  332. ねばくらミニでのポータルとサーヴァント(ねばくらミニ書籍版P14)。
  333. ・「ポータル」なら威力ロールに+30してよい。
  334. ・「サーヴァント」は自身が攻撃の対象になったとき、対象を自身のサーヴァントに変更してよい。
  335. TEXT
  336. 'CHAR1L' => <<~TEXT,
  337. ・所属表(2D6またはRoC。基本ルール書籍版P33)
  338. 2, 無職/専業主婦/専業主夫
  339. 3, パート・アルバイト
  340. 4, 中学生
  341. 5, 高校生
  342. 6, 大学生
  343. 7, 短大/専門学校生
  344. 8, 会社員
  345. 9, 公務員
  346. 10, 個人事業主
  347. 11, フリーランス
  348. 12, 経営者
  349. TEXT
  350. 'CHAR2L' => <<~TEXT,
  351. ・趣味表(2D6またはRoC。基本ルール書籍版P38)
  352. 2, プログラミング/ハッキング
  353. 3, テレビゲーム/ボードゲーム
  354. 4, 楽器演奏/作曲/編曲/DTM
  355. 5, 工芸/アクセサリー/プラモデル制作
  356. 6, イラスト/モデリング/デザイン
  357. 7, 電子工作/機械工作
  358. 8, 野球/サッカー/バスケ/テニス/バレエ/
  359. 9, ファッション
  360. 10, 自転車/BMX/バイク/車
  361. 11, ライトノベル/漫画/アニメ
  362. 12, ペット/ピクシー育成/生物観察
  363. TEXT
  364. 'CHAR3L' => <<~TEXT,
  365. ・リビド武装形状表(2D6またはRoC。基本ルール書籍版P39)
  366. 2, 模様。輝く五芒星や、巨大な数字など
  367. 3, 人型。想い人、アニメキャラ、衣服など
  368. 4, 魔法または超能力。炎や、謎のオーラなど
  369. 5, 獣。調教された犬、カラス、ヘビなど
  370. 6, 銃。拳銃、ライフル、火縄銃など
  371. 7, 近接武器。ナイフ、バールのようなものなど
  372. 8, 異形。巨大化した体や鉤爪、伸びる腕など
  373. 9, ドローン。航空機タイプや四足歩行タイプなど
  374. 10, モンスター。ゴーレム、悪魔、動く植物など
  375. 11, 乗り物(乗ることは出来ないので注意)。車、戦闘機など。
  376. 12, 他のどれでもない君のオリジナルのなにか
  377. TEXT
  378. 'NAYA1L' => <<~TEXT,
  379. ●悩みの詳細表・愛/Love:得意方向(正面)(2D6またはRoC。基本ルール書籍版P49)
  380. 2, オレには彼女が居るはずなのに誰にも見えない
  381. 3, 好きになった人が同性。でも将来的には子供がほしい……
  382. 4, あいつの彼女が可愛い
  383. 5, タレントを愛してしまったが当たり前だけど告白のしようもない
  384. 6, 好きなのに、あの人に告白できない。自分なんかが告白していい人じゃない……!
  385. 7, ●●のことが好き。でもそれを伝えてしまったら、今の関係が崩れてしまいそうで怖い
  386. 8, 相手が異性として見てくれない
  387. 9, 僕の彼女は遠く離れた大学への進学を悩んでいる。応援するべきか、引き止めるべきか
  388. 10, 一緒に遊びたいだけなのに、ついそっけない態度やいたずらをしてしまう
  389. 11, オレの彼女が可愛すぎてつらい
  390. 12, 好きになった人がピクシー(拡張現実の身体を持つ高性能AI)
  391. TEXT
  392. 'NAYA2L' => <<~TEXT,
  393. ●悩みの詳細表・体/Figure:得意方向(正面)(2D6またはRoC。基本ルール書籍版P49)
  394. 2, 過去の出来事が痛烈すぎて今が色褪せて見える
  395. 3, 我ながら醜い
  396. 4, 学校に行きたいけど行けない
  397. 5, 筋トレしてるけど筋肉がつかない。同じ部活のみんなはかっこいい体を手に入れているのに
  398. 6, 体重が気になる……ダイエットしなきゃ……でも、ごはんおいしい……
  399. 7, 身長があと数センチほしい。そしたらあいつを背を追い越せるのに!
  400. 8, 背が高いんだけど、もっと可愛い体に育ちたかった
  401. 9, 肌の白い人がうらやましい
  402. 10, 食べても食べてもお肉が付かない
  403. 11, 病気がちだ
  404. 12, 自分の美しさに酔いしれてしまう
  405. TEXT
  406. 'NAYA3L' => <<~TEXT,
  407. ●悩みの詳細表・才/Talent:得意方向(背面)(2D6またはRoC。基本ルール書籍版P49)
  408. 2, 将来何になりたいかと言われてもなんにも思いつかない
  409. 3, 俺様の能力はこんなものではないはずだ……! きっと明日起きたら秘められた真なる力にm
  410. 4, ああ妬ましい妬ましい。そう思ってしまう自分が嫌だが、わかっていてもやめられない
  411. 5, 妹の方が優秀。私だってこんなに勉強を頑張ってるのに、あの子と私のなにが違うの?
  412. 6, バカすぎて授業についていけない
  413. 7, バズりてぇな~~~俺もよぉ~~~~
  414. 8, アイツに勝てない!投手としても、バッターとしても!
  415. 9, この3年間サッカーに全てを捧げてきたのに、レギュラーになれない
  416. 10, 頑張りたいと思うけど気が多くて集中できない
  417. 11, 頑張って勉強したところでそれが何になるんだろうと思うと虚しい
  418. 12, 全力を出せる場所が欲しい。自分の才能がにくい
  419. TEXT
  420. 'NAYA4L' => <<~TEXT,
  421. ●悩みの詳細表・絆/Bonds:得意方向(側面)(2D6またはRoC。基本ルール書籍版P49)
  422. 2, 別に変な話をしているつもりはないのだけど同級生と会話が成立しない
  423. 3, 兄貴分に依存してしまい、1人で行動するのが怖い。アニキから離れたくない!
  424. 4, 飼っている犬が最近不機嫌。すぐ噛み付いてくる。なにかしてしまったのだろうか?
  425. 5, 来年、引っ越すことが決まった。一緒の高校に行こうねって約束したのに
  426. 6, いろんなことに首をつっこんでしまい、逆にうざがられてしまう
  427. 7, 一緒に遊んでいた親友が、最近よそよそしい気がする
  428. 8, なかなか友達ができない。できたとおもっても気づいたら話さなくなっている
  429. 9, 会話しているとへとへとになってる自分に時々気づく
  430. 10, 1人でいるほうがおちつくんだけど駄目なのか
  431. 11, 正直、クラスの連中の興味がどれもくだらなく思える
  432. 12, そもそも自分以外のヒトがなんで大事なのかさっぱり分からない
  433. TEXT
  434. 'NAYA5L' => <<~TEXT,
  435. ●悩みの詳細表・住/Home:得意方向(側面)(2D6またはRoC。基本ルール書籍版P49)
  436. 2, 親がもううるさくない
  437. 3, 親がいない。奨学金とバイトで学費を稼がなければ学校にも通えない
  438. 4, 学校を卒業したら家を出ることになっている。でも、親元を離れたくない
  439. 5, 親の再婚相手と上手くいかない。何故かきつく当たってしまう
  440. 6, 親と同じ仕事を目指しているけど認めてくれない、夢を否定される
  441. 7, お母さんが不治の病に侵されている
  442. 8, 家族の1人が家事が致命的に下手で家の内情がヤバい
  443. 9, 間違った場所に産まれてきた気がしてならない
  444. 10, 兄弟との仲が致命的に悪い。嫌われている
  445. 11, ことあるごとに親が「おまえはどうしようもないやつだ」と言ってくる
  446. 12, 門限が早い
  447. TEXT
  448. }.freeze
  449. TABLES = {
  450. 1 'CHAR1' => DiceTable::Table.new(
  451. '所属表',
  452. '2D6',
  453. [
  454. '無職/専業主婦/専業主夫',
  455. 'パート・アルバイト',
  456. '中学生',
  457. '高校生',
  458. '大学生',
  459. '短大/専門学校生',
  460. '会社員',
  461. '公務員',
  462. '個人事業主',
  463. 'フリーランス',
  464. '経営者'
  465. ]
  466. ),
  467. 'CHAR2' => DiceTable::Table.new(
  468. '趣味表',
  469. '2D6',
  470. [
  471. 'プログラミング/ハッキング',
  472. 'テレビゲーム/ボードゲーム',
  473. '楽器演奏/作曲/編曲/DTM',
  474. '工芸/アクセサリー/プラモデル制作',
  475. 'イラスト/モデリング/デザイン',
  476. '電子工作/機械工作',
  477. '野球/サッカー/バスケ/テニス/バレエ/',
  478. 'ファッション',
  479. '自転車/BMX/バイク/車',
  480. 'ライトノベル/漫画/アニメ',
  481. 'ペット/ピクシー育成/生物観察'
  482. ]
  483. ),
  484. 'CHAR3' => DiceTable::Table.new(
  485. 'リビド武装形状表',
  486. '2D6',
  487. [
  488. '模様。輝く五芒星や、巨大な数字など',
  489. '人型。想い人、アニメキャラ、衣服など',
  490. '魔法または超能力。炎や、謎のオーラなど',
  491. '獣。調教された犬、カラス、ヘビなど',
  492. '銃。拳銃、ライフル、火縄銃など',
  493. '近接武器。ナイフ、バールのようなものなど',
  494. '異形。巨大化した体や鉤爪、伸びる腕など',
  495. 'ドローン。航空機タイプや四足歩行タイプなど',
  496. 'モンスター。ゴーレム、悪魔、動く植物など',
  497. '乗り物(乗ることは出来ないので注意)。車、戦闘機など。',
  498. '他のどれでもない君のオリジナルのなにか'
  499. ]
  500. ),
  501. 'NAYA1' => DiceTable::Table.new(
  502. '悩みの詳細表・愛/Love',
  503. '2D6',
  504. [
  505. 'オレには彼女が居るはずなのに誰にも見えない',
  506. '好きになった人が同性。でも将来的には子供がほしい……',
  507. 'あいつの彼女が可愛い',
  508. 'タレントを愛してしまったが当たり前だけど告白のしようもない',
  509. '好きなのに、あの人に告白できない。自分なんかが告白していい人じゃない……!',
  510. '●●のことが好き。でもそれを伝えてしまったら、今の関係が崩れてしまいそうで怖い',
  511. '相手が異性として見てくれない',
  512. '僕の彼女は遠く離れた大学への進学を悩んでいる。応援するべきか、引き止めるべきか',
  513. '一緒に遊びたいだけなのに、ついそっけない態度やいたずらをしてしまう',
  514. 'オレの彼女が可愛すぎてつらい',
  515. '好きになった人がピクシー(拡張現実の身体を持つ高性能AI)'
  516. ]
  517. ),
  518. 'NAYA2' => DiceTable::Table.new(
  519. '悩みの詳細表・体/Figure',
  520. '2D6',
  521. [
  522. '過去の出来事が痛烈すぎて今が色褪せて見える',
  523. '我ながら醜い',
  524. '学校に行きたいけど行けない',
  525. '筋トレしてるけど筋肉がつかない。同じ部活のみんなはかっこいい体を手に入れているのに',
  526. '体重が気になる……ダイエットしなきゃ……でも、ごはんおいしい……',
  527. '身長があと数センチほしい。そしたらあいつを背を追い越せるのに!',
  528. '背が高いんだけど、もっと可愛い体に育ちたかった',
  529. '肌の白い人がうらやましい',
  530. '食べても食べてもお肉が付かない',
  531. '病気がちだ',
  532. '自分の美しさに酔いしれてしまう'
  533. ]
  534. ),
  535. 'NAYA3' => DiceTable::Table.new(
  536. '悩みの詳細表・才/Talent',
  537. '2D6',
  538. [
  539. '将来何になりたいかと言われてもなんにも思いつかない',
  540. '俺様の能力はこんなものではないはずだ……! きっと明日起きたら秘められた真なる力にm',
  541. 'ああ妬ましい妬ましい。そう思ってしまう自分が嫌だが、わかっていてもやめられない',
  542. '妹の方が優秀。私だってこんなに勉強を頑張ってるのに、あの子と私のなにが違うの?',
  543. 'バカすぎて授業についていけない',
  544. 'バズりてぇな~~~俺もよぉ~~~~',
  545. 'アイツに勝てない!投手としても、バッターとしても!',
  546. 'この3年間サッカーに全てを捧げてきたのに、レギュラーになれない',
  547. '頑張りたいと思うけど気が多くて集中できない',
  548. '頑張って勉強したところでそれが何になるんだろうと思うと虚しい',
  549. '全力を出せる場所が欲しい。自分の才能がにくい'
  550. ]
  551. ),
  552. 'NAYA4' => DiceTable::Table.new(
  553. '悩みの詳細表・絆/Bonds',
  554. '2D6',
  555. [
  556. '別に変な話をしているつもりはないのだけど同級生と会話が成立しない',
  557. '兄貴分に依存してしまい、1人で行動するのが怖い。アニキから離れたくない!',
  558. '飼っている犬が最近不機嫌。すぐ噛み付いてくる。なにかしてしまったのだろうか?',
  559. '来年、引っ越すことが決まった。一緒の高校に行こうねって約束したのに',
  560. 'いろんなことに首をつっこんでしまい、逆にうざがられてしまう',
  561. '一緒に遊んでいた親友が、最近よそよそしい気がする',
  562. 'なかなか友達ができない。できたとおもっても気づいたら話さなくなっている',
  563. '会話しているとへとへとになってる自分に時々気づく',
  564. '1人でいるほうがおちつくんだけど駄目なのか',
  565. '正直、クラスの連中の興味がどれもくだらなく思える',
  566. 'そもそも自分以外のヒトがなんで大事なのかさっぱり分からない'
  567. ]
  568. ),
  569. 'NAYA5' => DiceTable::Table.new(
  570. '悩みの詳細表・住/Home',
  571. '2D6',
  572. [
  573. '親がもううるさくない',
  574. '親がいない。奨学金とバイトで学費を稼がなければ学校にも通えない',
  575. '学校を卒業したら家を出ることになっている。でも、親元を離れたくない',
  576. '親の再婚相手と上手くいかない。何故かきつく当たってしまう',
  577. '親と同じ仕事を目指しているけど認めてくれない、夢を否定される',
  578. 'お母さんが不治の病に侵されている',
  579. '家族の1人が家事が致命的に下手で家の内情がヤバい',
  580. '間違った場所に産まれてきた気がしてならない',
  581. '兄弟との仲が致命的に悪い。嫌われている',
  582. 'ことあるごとに親が「おまえはどうしようもないやつだ」と言ってくる',
  583. '門限が早い'
  584. ]
  585. ),
  586. }.freeze
  587. 1 ALIAS_TEXTS = {
  588. "ARTS" => "ARTS1",
  589. }.freeze
  590. # ダイスボットで使用するコマンドを配列で列挙する
  591. 1 register_prefix('\d+NC', '\d+D6?([\+\-\d]*)>=\d+', TEXTS.keys, TABLES.keys, ALIAS_TEXTS.keys)
  592. end
  593. end
  594. end

lib/bcdice/game_system/NightWizard.rb

98.28% lines covered

94.29% branches covered

116 relevant lines. 114 lines covered and 2 lines missed.
35 total branches, 33 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/normalize"
  3. 1 require "bcdice/format"
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class NightWizard < Base
  7. # ゲームシステムの識別子
  8. 1 ID = 'NightWizard'
  9. # ゲームシステム名
  10. 1 NAME = 'ナイトウィザード The 2nd Edition'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = 'ないとういさあと2'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  15. ・判定用コマンド (aNW+b@x#y$z+c)
  16.   a : 基本値
  17.   b : 常時に準じる特技による補正
  18.   c : 常時以外の特技、および支援効果による補正(ファンブル時には適用されない)
  19.   x : クリティカル値のカンマ区切り(省略時 10)
  20.   y : ファンブル値のカンマ区切り(省略時 5)
  21.   z : プラーナによる達成値補正のプラーナ消費数(ファンブル時には適用されない)
  22.  クリティカル値、ファンブル値が無い場合は1や13などのあり得ない数値を入れてください。
  23.  例)12NW-5@7#2$3 1NW 50nw+5@7,10#2,5 50nw-5+10@7,10#2,5+15+25
  24. INFO_MESSAGE_TEXT
  25. 1 register_prefix('([-+]?\d+)?NW', '2R6')
  26. 1 def initialize(command)
  27. 109 super(command)
  28. 109 @nw_command = "NW"
  29. end
  30. # @return [String, nil]
  31. 1 def eval_game_system_specific_command(string)
  32. 109 cmd = parse_nw(string) || parse_2r6(string)
  33. 109 else: 109 then: 0 unless cmd
  34. return nil
  35. end
  36. 109 total, interim_expr, status = roll_nw(cmd)
  37. result =
  38. 109 then: 4 else: 105 if cmd.cmp_op
  39. 4 then: 2 else: 2 total.send(cmd.cmp_op, cmd.target_number) ? "成功" : "失敗"
  40. end
  41. sequence = [
  42. 109 "(#{cmd})",
  43. interim_expr,
  44. status,
  45. total.to_s,
  46. result,
  47. ].compact
  48. 109 return sequence.join(" > ")
  49. end
  50. 1 private
  51. 1 class Parsed
  52. # @return [Array<Integer>] クリティカルになる出目の一覧
  53. 1 attr_accessor :critical_numbers
  54. # @return [Array<Integer>] ファンブルになる出目の一覧
  55. 1 attr_accessor :fumble_numbers
  56. # @return [Integer, nil] プラーナによる補正
  57. 1 attr_accessor :prana
  58. # @return [Integer] ファンブルでない時に適用される修正値
  59. 1 attr_accessor :active_modify_number
  60. # @return [Symbol, nil] 比較演算子
  61. 1 attr_accessor :cmp_op
  62. # @return [Integer, nil] 目標値
  63. 1 attr_accessor :target_number
  64. end
  65. 1 class ParsedNW < Parsed
  66. # @return [Integer] 判定の基礎値
  67. 1 attr_accessor :base
  68. # @return [Integer] 修正値
  69. 1 attr_accessor :modify_number
  70. 1 def initialize(command)
  71. 60 super()
  72. 60 @command = command
  73. end
  74. # 常に適用される修正値を返す
  75. #
  76. # @return [Integer]
  77. 1 def passive_modify_number
  78. 60 @base + @modify_number
  79. end
  80. # @return [String]
  81. 1 def to_s
  82. 60 then: 11 else: 49 base = @base.zero? ? nil : @base
  83. 60 modify_number = Format.modifier(@modify_number)
  84. 60 active_modify_number = Format.modifier(@active_modify_number)
  85. 60 dollar = @prana && "$#{@prana}"
  86. 60 return "#{base}#{@command}#{modify_number}@#{@critical_numbers.join(',')}##{@fumble_numbers.join(',')}#{dollar}#{active_modify_number}#{@cmp_op}#{@target_number}"
  87. end
  88. end
  89. 1 class Parsed2R6 < Parsed
  90. # @return [Integer] 常に適用される修正値
  91. 1 attr_accessor :passive_modify_number
  92. # @return [String]
  93. 1 def to_s
  94. 49 "2R6M[#{@passive_modify_number},#{@active_modify_number}]C[#{@critical_numbers.join(',')}]F[#{@fumble_numbers.join(',')}]#{@cmp_op}#{@target_number}"
  95. end
  96. end
  97. # @return [ParsedNW, nil]
  98. 1 def parse_nw(string)
  99. 109 m = /^([-+]?\d+)?#{@nw_command}((?:[-+]\d+)+)?(?:@(\d+(?:,\d+)*))?(?:#(\d+(?:,\d+)*))?(?:\$(\d+))?((?:[-+]\d+)+)?(?:([>=]+)(\d+))?$/.match(string)
  100. 109 else: 60 then: 49 unless m
  101. 49 return nil
  102. end
  103. 60 command = ParsedNW.new(@nw_command)
  104. 60 command.base = m[1].to_i
  105. 60 command.modify_number = ArithmeticEvaluator.eval(m[2])
  106. 60 then: 48 else: 12 command.critical_numbers = m[3] ? m[3].split(',').map(&:to_i) : [10]
  107. 60 then: 48 else: 12 command.fumble_numbers = m[4] ? m[4].split(',').map(&:to_i) : [5]
  108. 60 then: 3 else: 57 command.prana = m[5]&.to_i
  109. 60 command.active_modify_number = ArithmeticEvaluator.eval(m[6])
  110. 60 command.cmp_op = Normalize.comparison_operator(m[7])
  111. 60 then: 2 else: 58 command.target_number = m[8]&.to_i
  112. 60 return command
  113. end
  114. # @return [Parsed2R6, nil]
  115. 1 def parse_2r6(string)
  116. 49 m = /^2R6m\[([-+]?\d+(?:[-+]\d+)*)(?:,([-+]?\d+(?:[-+]\d+)*))?\](?:c\[(\d+(?:,\d+)*)\])?(?:f\[(\d+(?:,\d+)*)\])?(?:([>=]+)(\d+))?/i.match(string)
  117. 49 else: 49 then: 0 unless m
  118. return nil
  119. end
  120. 49 command = Parsed2R6.new
  121. 49 command.passive_modify_number = ArithmeticEvaluator.eval(m[1])
  122. 49 command.active_modify_number = ArithmeticEvaluator.eval(m[2])
  123. 49 then: 39 else: 10 command.critical_numbers = m[3] ? m[3].split(',').map(&:to_i) : [10]
  124. 49 then: 39 else: 10 command.fumble_numbers = m[4] ? m[4].split(',').map(&:to_i) : [5]
  125. 49 command.cmp_op = Normalize.comparison_operator(m[5])
  126. 49 then: 2 else: 47 command.target_number = m[6]&.to_i
  127. 49 return command
  128. end
  129. 1 def roll_nw(parsed)
  130. 109 @critical_numbers = parsed.critical_numbers
  131. 109 @fumble_numbers = parsed.fumble_numbers
  132. 109 @total = 0
  133. 109 @interim_expr = ""
  134. 109 @status = nil
  135. 109 status = roll_once_first()
  136. 109 body: 21 while status == :critical
  137. 21 status = roll_once()
  138. end
  139. 109 then: 2 else: 107 if status != :fumble && parsed.prana
  140. 2 dice_list = @randomizer.roll_barabara(parsed.prana, 6)
  141. 2 prana_bonus = dice_list.sum()
  142. 2 prana_list = dice_list.join(",")
  143. 2 @total += prana_bonus
  144. 2 @interim_expr += "+#{prana_bonus}[#{prana_list}]"
  145. end
  146. base =
  147. 109 then: 15 if status == :fumble
  148. 15 fumble_base_number(parsed)
  149. else: 94 else
  150. 94 parsed.passive_modify_number + parsed.active_modify_number
  151. end
  152. 109 @total += base
  153. 109 @interim_expr = base.to_s + @interim_expr
  154. 109 return @total, @interim_expr, @status
  155. end
  156. # @return [Symbol, nil]
  157. 1 def roll_once(fumbleable = false)
  158. 130 dice_list = @randomizer.roll_barabara(2, 6)
  159. 130 dice_value = dice_list.sum()
  160. 130 dice_str = dice_list.join(",")
  161. 130 then: 15 if fumbleable && @fumble_numbers.include?(dice_value)
  162. 15 @total -= 10
  163. 15 @interim_expr += "-10[#{dice_str}]"
  164. 15 @status = "ファンブル"
  165. 15 else: 115 return :fumble
  166. 115 then: 21 elsif @critical_numbers.include?(dice_value)
  167. 21 @total += 10
  168. 21 @interim_expr += "+10[#{dice_str}]"
  169. 21 @status = "クリティカル"
  170. 21 return :critical
  171. else: 94 else
  172. 94 @total += dice_value
  173. 94 @interim_expr += "+#{dice_value}[#{dice_str}]"
  174. 94 return nil
  175. end
  176. end
  177. # @return [Symbol, nil]
  178. 1 def roll_once_first
  179. 109 roll_once(true)
  180. end
  181. # @return [Integer]
  182. 1 def fumble_base_number(parsed)
  183. 14 parsed.passive_modify_number
  184. end
  185. end
  186. end
  187. end

lib/bcdice/game_system/NightWizard3rd.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/NightWizard'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class NightWizard3rd < NightWizard
  6. # ゲームシステムの識別子
  7. 1 ID = 'NightWizard3rd'
  8. # ゲームシステム名
  9. 1 NAME = 'ナイトウィザード The 3rd Edition'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'ないとういさあと3'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・判定用コマンド (aNW+b@x#y$z+c)
  15.   a : 基本値
  16.   b : 常時に準じる特技による補正
  17.   c : 常時以外の特技、および支援効果による補正
  18.   x : クリティカル値のカンマ区切り(省略時 10)
  19.   y : ファンブル値のカンマ区切り(省略時 5)
  20.   z : プラーナによる達成値補正のプラーナ消費数(ファンブル時には適用されない)
  21.  クリティカル値、ファンブル値が無い場合は1や13などのあり得ない数値を入れてください。
  22.  例)12NW-5@7#2$3 1NW 50nw+5@7,10#2,5 50nw-5+10@7,10#2,5+15+25
  23. INFO_MESSAGE_TEXT
  24. 1 register_prefix('([-+]?\d+)?NW', '2R6')
  25. 1 def fumble_base_number(parsed)
  26. 1 parsed.passive_modify_number + parsed.active_modify_number
  27. end
  28. end
  29. end
  30. end

lib/bcdice/game_system/NightmareHunterDeep.rb

98.0% lines covered

85.0% branches covered

50 relevant lines. 49 lines covered and 1 lines missed.
20 total branches, 17 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/format"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class NightmareHunterDeep < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'NightmareHunterDeep'
  8. # ゲームシステム名
  9. 1 NAME = 'ナイトメアハンター=ディープ'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'ないとめあはんたあていいふ'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. 判定(xD6+y>=a, xD6+y, xD6)
  15. 出目6の個数をカウントして、その4倍を合計値に加算します。
  16. また、宿命を獲得したか表示します。
  17. Lv目標値 (xD6+y>=LVn, xD6+y>=NLn)
  18. レベルで目標値を指定することができます。
  19. LVn -> n*5+1, NLn -> n*5+5 に変換されます。
  20. 目標値'?' (xD6+y>=?)
  21. 目標値を '?' にすると何Lv成功か、何NL成功かを表示します。
  22. ※判定コマンドは xD6 から始まる必要があります。また xD6 が複数あると反応しません。
  23. INFO_MESSAGE_TEXT
  24. 1 register_prefix('\d+D6')
  25. 1 def initialize(command)
  26. 51 super(command)
  27. 51 @sort_add_dice = true
  28. end
  29. 1 def eval_game_system_specific_command(command)
  30. 51 command = command
  31. 10 .sub(/Lv(\d+)/i) { (Regexp.last_match(1).to_i * 5 - 1).to_s }
  32. 10 .sub(/NL(\d+)/i) { (Regexp.last_match(1).to_i * 5 + 5).to_s }
  33. 51 parser = Command::Parser.new(/\d+D6/, round_type: round_type)
  34. .restrict_cmp_op_to(nil, :>=)
  35. .enable_question_target()
  36. 51 cmd = parser.parse(command)
  37. 51 else: 51 then: 0 unless cmd
  38. return nil
  39. end
  40. 51 times = cmd.command.to_i
  41. 51 dice_list = @randomizer.roll_barabara(times, 6).sort
  42. 51 dice_total = dice_list.sum()
  43. 51 total = dice_total + cmd.modify_number
  44. 51 suffix, revision = dice_revision(dice_list)
  45. 51 total += revision
  46. 51 then: 1 else: 50 target = cmd.question_target? ? "?" : cmd.target_number
  47. 51 result = result_text(total, cmd.cmp_op, target)
  48. sequence = [
  49. 51 "(#{cmd})",
  50. interim_expr(cmd, dice_total, dice_list),
  51. expr_with_revision(dice_total + cmd.modify_number, suffix),
  52. total,
  53. result,
  54. fate(dice_list),
  55. ].compact
  56. 51 return sequence.join(" > ")
  57. end
  58. 1 def result_text(total, cmp_op, target)
  59. 51 else: 51 then: 0 return nil unless cmp_op == :>=
  60. 51 then: 50 else: 1 if target != "?"
  61. 50 then: 34 else: 16 return total >= target ? "成功" : "失敗"
  62. end
  63. 1 success_lv = (total + 1) / 5
  64. 1 success_nl = (total - 5) / 5
  65. 1 then: 1 else: 0 return success_lv > 0 ? "Lv#{success_lv}/NL#{success_nl}成功" : "失敗"
  66. end
  67. # ナイトメアハンターディープ用宿命表示
  68. 1 def fate(dice_list)
  69. 51 then: 24 else: 27 dice_list.count(1) > 0 ? "宿命獲得" : nil
  70. end
  71. 1 def interim_expr(cmd, dice_total, dice_list)
  72. 51 then: 41 else: 10 if dice_list.size > 1 || cmd.modify_number != 0
  73. 41 modifier = Format.modifier(cmd.modify_number)
  74. 41 "#{dice_total}[#{dice_list.join(',')}]#{modifier}"
  75. end
  76. end
  77. 1 def expr_with_revision(total, suffix)
  78. 51 then: 23 else: 28 suffix ? "#{total}#{suffix}" : nil
  79. end
  80. 1 def dice_revision(dice_list)
  81. 51 count6 = dice_list.count(6)
  82. 51 then: 23 if count6 > 0
  83. 23 return "+#{count6}*4", count6 * 4
  84. else: 28 else
  85. 28 return nil, 0
  86. end
  87. end
  88. end
  89. end
  90. end

lib/bcdice/game_system/NinjaSlayer.rb

97.78% lines covered

91.67% branches covered

90 relevant lines. 88 lines covered and 2 lines missed.
24 total branches, 22 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/common_command/barabara_dice'
  3. 1 require 'bcdice/dice_table/table'
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class NinjaSlayer < Base
  7. # ゲームシステムの識別子
  8. 1 ID = 'NinjaSlayer'
  9. # ゲームシステム名
  10. 1 NAME = 'ニンジャスレイヤーTRPG'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = 'にんしやすれいやあTRPG'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = <<~MESSAGETEXT
  15. ・通常判定 NJ
  16.  NJx[y] or NJx@y or NJx
  17.  x=判定ダイス y=難易度 省略時はNORMAL(4)
  18.  例:NJ4@H 難易度HARD、判定ダイス4で判定
  19. ・回避判定 EV
  20.  EVx[y]/z or EVx@y/z or EVx/z or EVx[y] or EVx@y or EVx
  21.  x=判定ダイス y=難易度 z=攻撃側の成功数(省略可) 難易度を省略時はNORMAL(4)
  22.  攻撃側の成功数を指定した場合、カウンターカラテ発生時には表示
  23.  例:EV5/3 難易度NORMAL(省略時)、判定ダイス5、攻撃側の成功数3で判定
  24. ・近接攻撃 AT
  25.  ATx[y] or ATx@y or ATx
  26.  x=判定ダイス y=難易度 省略時はNORMAL(4) サツバツ!発生時には表示
  27.  例:AT6[H] 難易度HARD,判定ダイス5で近接攻撃の判定
  28. ・サツバツ判定 SB
  29. ・電子戦 EL
  30.  ELx[y] or ELx@y or ELx
  31.  x=判定ダイス y=難易度 省略時はNORMAL(4)
  32.  例:EL6[H] 難易度HARD,判定ダイス5で電子戦の判定
  33. ・難易度
  34.  KIDS=K,EASY=E,NORMAL=N,HARD=H,ULTRA HARD=UH 数字にも対応
  35. ※上記コマンド群は『ニンジャスレイヤーTRPG コア・ルールブック』に対応していません。コア・ルールブックで遊ぶ場合には『ニンジャスレイヤーTRPG 2版』のコマンドを利用してください。
  36. MESSAGETEXT
  37. 1 def initialize(command)
  38. 59 super(command)
  39. 59 @default_cmp_op = :>=
  40. 59 @default_target_number = 4
  41. end
  42. # 難易度の値の正規表現
  43. 1 DIFFICULTY_VALUE_RE = /UH|[2-6KENH]/i.freeze
  44. # 難易度の正規表現
  45. 1 DIFFICULTY_RE = /\[(#{DIFFICULTY_VALUE_RE})\]|@(#{DIFFICULTY_VALUE_RE})/io.freeze
  46. # 通常判定の正規表現
  47. 1 NJ_RE = /\A(S)?NJ(\d+)#{DIFFICULTY_RE}?\z/io.freeze
  48. # 回避判定の正規表現
  49. 1 EV_RE = %r{\AEV(\d+)#{DIFFICULTY_RE}?(?:/(\d+))?\z}io.freeze
  50. # 近接攻撃の正規表現
  51. 1 AT_RE = /\AAT(\d+)#{DIFFICULTY_RE}?\z/io.freeze
  52. # 電子戦の正規表現
  53. 1 EL_RE = /\AEL(\d+)#{DIFFICULTY_RE}?\z/io.freeze
  54. # 回避判定のノード
  55. 1 EV = Struct.new(:num, :difficulty, :targetValue)
  56. # 近接攻撃のノード
  57. 1 AT = Struct.new(:num, :difficulty)
  58. # 電子戦のノード
  59. 1 EL = Struct.new(:num, :difficulty)
  60. # 難易度の文字表現から整数値への対応
  61. 1 DIFFICULTY_SYMBOL_TO_INTEGER = {
  62. 'K' => 2,
  63. 'E' => 3,
  64. 'N' => 4,
  65. 'H' => 5,
  66. 'UH' => 6
  67. }.freeze
  68. 1 def change_text(str)
  69. 84 m = NJ_RE.match(str)
  70. 84 else: 46 then: 38 return str unless m
  71. 46 b_roll = bRollCommand(m[2], integerValueOfDifficulty(m[3] || m[4]))
  72. 46 return "#{m[1]}#{b_roll}"
  73. end
  74. 1 def eval_game_system_specific_command(command)
  75. 34 debug('eval_game_system_specific_command begin string', command)
  76. 34 then: 2 else: 32 if (table = TABLES[command])
  77. 2 return table.roll(randomizer)
  78. end
  79. 32 case node = parse(command)
  80. when: 10 when EV
  81. 10 return executeEV(node)
  82. when: 11 when AT
  83. 11 return executeAT(node)
  84. when: 11 when EL
  85. 11 return executeEL(node)
  86. else: 0 else
  87. return nil
  88. end
  89. end
  90. 1 private
  91. # 構文解析する
  92. # @param [String] command コマンド文字列
  93. # @return [EV, AT, EL, nil]
  94. 1 def parse(command)
  95. 32 case command
  96. when: 10 when EV_RE
  97. 10 return parseEV(Regexp.last_match)
  98. when: 11 when AT_RE
  99. 11 return parseAT(Regexp.last_match)
  100. when: 11 when EL_RE
  101. 11 return parseEL(Regexp.last_match)
  102. else: 0 else
  103. return nil
  104. end
  105. end
  106. # 正規表現のマッチ情報から回避判定ノードを作る
  107. # @param [MatchData] m 正規表現のマッチ情報
  108. # @return [EV]
  109. 1 def parseEV(m)
  110. 10 num = m[1].to_i
  111. 10 difficulty = integerValueOfDifficulty(m[2] || m[3])
  112. 10 then: 8 else: 2 targetValue = m[4]&.to_i
  113. 10 return EV.new(num, difficulty, targetValue)
  114. end
  115. # 正規表現のマッチ情報から近接攻撃ノードを作る
  116. # @param [MatchData] m 正規表現のマッチ情報
  117. # @return [AT]
  118. 1 def parseAT(m)
  119. 11 num = m[1].to_i
  120. 11 difficulty = integerValueOfDifficulty(m[2] || m[3])
  121. 11 return AT.new(num, difficulty)
  122. end
  123. # 正規表現のマッチ情報から電子戦ノードを作る
  124. # @param [MatchData] m 正規表現のマッチ情報
  125. # @return [EL]
  126. 1 def parseEL(m)
  127. 11 num = m[1].to_i
  128. 11 difficulty = integerValueOfDifficulty(m[2] || m[3])
  129. 11 return EL.new(num, difficulty)
  130. end
  131. # 回避判定を行う
  132. # @param [EV] ev 回避判定ノード
  133. # @return [String] 回避判定結果
  134. 1 def executeEV(ev)
  135. 10 command = bRollCommand(ev.num, ev.difficulty)
  136. 10 roll_result = BCDice::CommonCommand::BarabaraDice.eval(command, self, @randomizer)
  137. 10 parts = [roll_result.text]
  138. 10 then: 5 else: 5 if ev.targetValue && roll_result.success_num > ev.targetValue
  139. 5 parts.push("カウンターカラテ!!")
  140. end
  141. 10 return parts.join(" > ")
  142. end
  143. # 近接攻撃を行う
  144. # @param [AT] at 近接攻撃ノード
  145. # @return [String] 近接攻撃結果
  146. 1 def executeAT(at)
  147. 11 command = bRollCommand(at.num, at.difficulty)
  148. 11 roll_result = BCDice::CommonCommand::BarabaraDice.eval(command, self, @randomizer)
  149. 11 num_of_max_values = roll_result.last_dice_list.count(6)
  150. 11 parts = [roll_result.text]
  151. 11 then: 8 else: 3 if num_of_max_values >= 2
  152. 8 parts.push("サツバツ!!")
  153. end
  154. 11 return parts.join(" > ")
  155. end
  156. # 電子戦を行う
  157. # @param [EL] el 電子戦ノード
  158. # @return [String] 電子戦結果
  159. 1 def executeEL(el)
  160. 11 command = bRollCommand(el.num, el.difficulty)
  161. 11 roll_result = BCDice::CommonCommand::BarabaraDice.eval(command, self, @randomizer)
  162. 11 values = roll_result.last_dice_list
  163. 11 num_of_max_values = values.count(6)
  164. 55 sum_of_true_values = values.count { |v| v >= el.difficulty }
  165. 11 then: 7 else: 4 if num_of_max_values >= 1
  166. return [
  167. 7 "#{roll_result.text} + #{num_of_max_values}",
  168. sum_of_true_values + num_of_max_values
  169. ].join(" > ")
  170. end
  171. 4 return roll_result.text
  172. end
  173. # 難易度の整数値を返す
  174. # @param [String, nil] s 難易度表記
  175. # @return [Integer] 難易度の整数値
  176. # @raise [KeyError, IndexError] 無効な難易度表記が渡された場合。
  177. #
  178. # sは2から6までの数字あるいは'K', 'E', 'N', 'H', 'UH'。
  179. # sがnilの場合は 4 を返す。
  180. 1 def integerValueOfDifficulty(s)
  181. 78 else: 65 then: 13 return 4 unless s
  182. 65 then: 15 else: 50 return s.to_i if /\A[2-6]\z/.match(s)
  183. 50 return DIFFICULTY_SYMBOL_TO_INTEGER.fetch(s.upcase)
  184. end
  185. # バラバラロールのコマンドを返す
  186. # @param [#to_s] num ダイス数
  187. # @param [#to_s] difficulty 難易度
  188. # @return [String]
  189. 1 def bRollCommand(num, difficulty)
  190. 78 "#{num}B6>=#{difficulty}"
  191. end
  192. # サツバツ表
  193. 1 SATSUBATSU_TABLE = [
  194. '「死ねーッ!」腹部に強烈な一撃! 敵はくの字に折れ曲がり、ワイヤーアクションめいて吹っ飛んだ!:本来のダメージ+1ダメージを与える。敵は後方の壁または障害物に向かって、何マスでもまっすぐ弾き飛ばされる(他のキャラのいるマスは通過する)。壁または障害物に接触した時点で、敵はさらに1ダメージを受ける。敵はこの激突ダメージに対して改めて『回避判定』を行っても良い。',
  195. '「イヤーッ!」頭部への痛烈なカラテ! 眼球破壊もしくは激しい脳震盪が敵を襲う!:本来のダメージを与える。さらに敵の【ニューロン】と【ワザマエ】がそれぞれ1ずつ減少する(これによる最低値は1)。残虐ボーナスにより【万札】がD3発生。この攻撃を【カルマ:善】のキャラに対して行ってしまった場合、【DKK】がD3上昇する。',
  196. '「苦しみ抜いて死ぬがいい」急所を情け容赦なく破壊!:本来のダメージ+1ダメージを与える。耐え難い苦痛により、敵は【精神力】が-2され、【ニューロン】が1減少する(これによる最低値は1)。残虐ボーナスにより【万札】がD3発生。この攻撃を【カルマ:善】のキャラに対して行ってしまった場合、【DKK】がD3上昇する。',
  197. '「逃げられるものなら逃げてみよ」敵の脚を粉砕!:本来のダメージを与える。さらに敵の【脚力】がD3減少する(最低値は1)。残虐ボーナスにより【万札】がD3発生。この攻撃を【カルマ:善】のキャラに対して行ってしまった場合、【DKK】がD3上昇する。',
  198. '「これで手も足も出まい!」敵の両腕を切り飛ばした! 鮮血がスプリンクラーめいて噴き出す!:本来のダメージ+1ダメージを与える。さらに敵の【ワザマエ】と【カラテ】がそれぞれ2減少する(最低値は1)。残虐ボーナスにより【万札】がD3発生。この攻撃を【カルマ:善】のキャラに対して行ってしまった場合、【DKK】がD3上昇する。',
  199. '「イイイヤアアアアーーーーッ!」ヤリめいたチョップが敵の胸を貫通! さらに心臓を掴み取り、握りつぶした! ナムアミダブツ!:敵は残り【体力】に関係なく即死する。残虐ボーナスにより【万札】がD6発生。この攻撃を【カルマ:善】のキャラに対して行ってしまった場合、【DKK】がD6上昇する。'
  200. ].freeze
  201. # 表の定義
  202. TABLES = {
  203. 1 'SB' => DiceTable::Table.new(
  204. 'サツバツ表',
  205. '1D6',
  206. SATSUBATSU_TABLE
  207. )
  208. }.freeze
  209. # ダイスボットで使用するコマンドを配列で列挙する
  210. 1 register_prefix(
  211. 'NJ',
  212. 'EV',
  213. 'AT',
  214. 'EL',
  215. TABLES.keys
  216. )
  217. end
  218. end
  219. end

lib/bcdice/game_system/NinjaSlayer2.rb

97.48% lines covered

91.11% branches covered

119 relevant lines. 116 lines covered and 3 lines missed.
45 total branches, 41 branches covered and 4 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class NinjaSlayer2 < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "NinjaSlayer2"
  7. # ゲームシステム名
  8. 1 NAME = "ニンジャスレイヤーTRPG 2版"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "にんしやすれいやあTRPG2"
  11. 1 HELP_MESSAGE = <<~TEXT
  12. - K{x1},{x2},...,{xn}
  13. 難易度K([K]ids)の成功判定({x1}B6>=2)を、ダイス{x1}個({x2}~を指定した場合はそれぞれ個々に)で実行します。
  14. 先頭の文字を変えることで、難易度E([E]asy),N([N]ormal),H([H]ard),U([U]ltra-hard)もしくはUH([U]ltra-[H]ard)でも実行可能です。(以下も同様)
  15. - K{x1},{x2},...,{xn}[>={y}]
  16. K{x1}のロールの結果を使って、[]内で指定された条件を満たすダイスの個数を追加で出力します。
  17. 判定式は「>=」の他に「>」「<=」「<」「=」「!=」が利用可能です。
  18. [=5][=6]のように複数記述することで、それぞれで追加判定が可能です。
  19. - K{x1},{x2},...,{xn}[S] or K{x1},{x2},...,{xn}[S{y}]
  20. - K{x1},{x2},...,{xn}[C] or K{x1},{x2},...,{xn}[C{y}]
  21. いずれもK{x1},{x2},...,{xn}[>={y}]のショートカットです。({y}省略時は固定値6で処理します。)
  22. 出力時のテキストが、Sの場合は「サツバツ!」に、Cの場合は「クリティカル!」になります。
  23. こちらも複数記述することで、それぞれで追加判定が可能です。
  24. - SB or SB@{x}
  25. {x}(1-6/省略時はd6)に対応したサツバツ([S]atz-[B]atz)・クリティカル表の内容を返します。
  26. - WS{x}
  27. {x}(1-12/省略不可)に対応する[W]as[s]hoi!判定(2d6<={x})を行います
  28. - WSE or WSE@{x}
  29. {x}(1-6/省略時はd6)に対応する死神のエントリー決定表([W]as[s]hoi! [E]ntry)の内容を返します。
  30. - NRS_E{x} or NRS_E{x}@{y} or NRS@{y}
  31. ダイス{x}個で難易度[E]asy(>=3)のNRS判定({x}省略時はスキップ)を行い、失敗した場合は{y}(1~7/省略時は難易度に応じたダイス目)に対応するNRS発狂表を返します。
  32. 「_E」部分を変更することで、難易度N,H,U,UHでも利用可能です。(Kはありません)
  33. TEXT
  34. # Base::eval_game_system_specific_commandの実装
  35. # @param command [String]
  36. # @return [String, nil]
  37. 1 def eval_game_system_specific_command(command)
  38. # @debug = true
  39. 19 debug("input: #{command}")
  40. begin
  41. 19 case command
  42. when RE_JUDGE_DICEROLL
  43. when: 6 # 2版用のダイス判定
  44. 6 proc_result = proc_dice_2nd(Regexp.last_match)
  45. # 結果は文字列と達成値という形で受け取る
  46. 6 then: 5 if proc_result[1] > 0
  47. 5 return Result.success(proc_result[0])
  48. else: 1 else
  49. 1 return Result.failure(proc_result[0])
  50. end
  51. else
  52. else: 13 # ダイスでなければ定型文処理
  53. 13 return proc_text(command)
  54. end
  55. rescue StandardError => e
  56. # 解析できずにエラーが出たら構文ミスと皆してnilを返す
  57. debug("#{e.message} \n#{e.backtrace}")
  58. return nil
  59. end
  60. end
  61. 1 private
  62. # 文字列stringを数値化する。nilの場合はdefaultで指定された値を返す
  63. # @param string [String]
  64. # @param default [Integer]
  65. # @return [Integer]
  66. 1 def s_to_i(string, default)
  67. 6 then: 3 else: 3 return string.nil? ? default : string.to_i
  68. end
  69. # 判定結果の出力テキストと成功数のカウントを返す。
  70. # @param dice_array [Array<Integer>]
  71. # @param difficulty [Integer]
  72. # @param cmp_op [String]
  73. # @param title_text [String]
  74. # @return [String, Integer]
  75. 1 def check_difficulty(dice_array, difficulty, cmp_op, title_text)
  76. 9 success_num = 0
  77. 9 success_dice = []
  78. 9 dice_array.each do |dice_value|
  79. 36 then: 19 else: 17 if dice_value.send(Normalize.comparison_operator(cmp_op), difficulty)
  80. 19 success_num += 1
  81. 19 success_dice.push(dice_value)
  82. end
  83. end
  84. 9 then: 1 else: 8 success_dice_s = success_dice.empty? ? "" : "[#{success_dice.sort.reverse.join(',')}]"
  85. 9 return "#{title_text}:#{success_num}#{success_dice_s}", success_num
  86. end
  87. # ダイス処理(2版用)
  88. # @param command [String]
  89. # @return [String, Integer]
  90. 1 def proc_dice_2nd(match)
  91. 6 output_text = ''
  92. 6 total_success_num = 0
  93. 6 difficulty = DIFFICULTY_SYMBOL_TO_INTEGER.fetch(match[1])
  94. 6 appendix = match[3]
  95. 6 match[2].split(",").each do |sub_command|
  96. 8 dice_num = sub_command.to_i
  97. # D6バラバラロール
  98. 8 roll_command = "#{dice_num}B6>=#{difficulty}"
  99. 8 roll_result = BCDice::CommonCommand::BarabaraDice.eval(roll_command, self, @randomizer)
  100. 8 output_text += "(#{roll_command}) > #{roll_result.last_dice_list.join(',')} > 成功数:#{roll_result.success_num}"
  101. 8 success_num = roll_result.success_num
  102. # Appendix部分の処理
  103. 8 else: 5 then: 3 unless appendix.nil?
  104. 3 debug("---- appendix: [#{appendix}]")
  105. 3 ap_command_array = appendix.split("\]\[")
  106. 3 ap_command_array.each do |ap_command|
  107. 9 debug("----- ap_command: #{ap_command}")
  108. 9 else: 0 case ap_command
  109. when RE_COUNT_SATZ_BATZ
  110. when: 3 # サツバツ!カウント
  111. 3 check_result = check_difficulty(roll_result.last_dice_list, s_to_i(Regexp.last_match[1], 6), ">=", "サツバツ!")
  112. 3 output_text += ", #{check_result[0]}"
  113. 3 success_num += check_result[1]
  114. when RE_COUNT_CRITICAL
  115. when: 3 # クリティカル!カウント
  116. 3 check_result = check_difficulty(roll_result.last_dice_list, s_to_i(Regexp.last_match[1], 6), ">=", "クリティカル!")
  117. 3 output_text += ", #{check_result[0]}"
  118. 3 success_num += check_result[1]
  119. when RE_COUNT_JUDGE
  120. when: 3 # 追加判定カウント
  121. 3 check_result = check_difficulty(roll_result.last_dice_list, Regexp.last_match[2].to_i, Regexp.last_match[1], "追加判定")
  122. 3 output_text += ", #{check_result[0]}"
  123. 3 success_num += check_result[1]
  124. end
  125. end
  126. end
  127. 8 output_text += " \n"
  128. 8 total_success_num += success_num
  129. end
  130. 6 return output_text, total_success_num
  131. end
  132. # サツバツ!の処理を実行する
  133. # @param type [Integer]
  134. # @return [Result]
  135. 1 def proc_satz_batz(type)
  136. # サツバツ判定(d6)
  137. 2 then: 1 if type > 0
  138. 1 return "サツバツ!!(#{type}) > #{translate('NinjaSlayer2.table.SATSUBATSU.items')[type - 1]}"
  139. else: 1 else
  140. 1 return DiceTable::Table.from_i18n("NinjaSlayer2.table.SATSUBATSU", @locale).roll(@randomizer)
  141. end
  142. end
  143. # Wasshoi!判定の処理を実行する
  144. # @param dkk [Integer]
  145. # @return [Result]
  146. 1 def proc_wasshoi(dkk)
  147. 2 dice_array = @randomizer.roll_barabara(2, 6)
  148. 2 output_text = "Wasshoi!判定(2D6) > (#{dice_array.join('+')}) > #{dice_array.sum()}"
  149. 2 then: 1 if dice_array.sum() > dkk
  150. 1 output_text += "(>#{dkk}) 判定失敗"
  151. 1 return Result.success(output_text)
  152. else: 1 else
  153. 1 output_text += "(<=#{dkk}) 判定成功!! \nニンジャスレイヤー=サンのエントリーだ!!"
  154. 1 return Result.failure(output_text)
  155. end
  156. end
  157. # Wasshoi!の処理を実行する
  158. # @param type [Integer]
  159. # @return [Result]
  160. 1 def proc_wasshoi_entry(type)
  161. # Wasshoi!判定
  162. 2 output_text = ""
  163. 2 then: 1 if type > 0
  164. 1 output_text += "ニンジャスレイヤー=サンのエントリー!!(#{type}) > #{translate('NinjaSlayer2.table.WASSHOI.items')[type - 1]}"
  165. else
  166. else: 1 # DKKの指定無し、もしくはロール結果がDKKを超えたら死神のエントリー決定表(d6)
  167. 1 table = DiceTable::Table.from_i18n("NinjaSlayer2.table.WASSHOI", @locale)
  168. 1 output_text += table.roll(@randomizer).to_s
  169. end
  170. 2 return output_text
  171. end
  172. # NRS判定の処理を実行する
  173. # @param dice_num [Integer]
  174. # @param dificulty_s [String]
  175. # @param type [Integer]
  176. # @return [Result]
  177. 1 def proc_nrs(dice_num, dificulty_s, type)
  178. # 難易度も乱数表の番号も指定が無ければコマンドミス
  179. 7 then: 1 else: 6 dificulty_i = dificulty_s.nil? ? 0 : DIFFICULTY_SYMBOL_TO_INTEGER.fetch(dificulty_s)
  180. 7 then: 0 else: 7 if dificulty_i == 0 && type == 0
  181. return nil
  182. end
  183. # NRS判定
  184. 7 output_text = ""
  185. 7 then: 6 else: 1 if dificulty_i > 0
  186. 6 roll_command = "#{dice_num}B6>=#{dificulty_i}"
  187. 6 roll_result = BCDice::CommonCommand::BarabaraDice.eval(roll_command, self, @randomizer)
  188. 6 output_text += "NRS判定(#{roll_command}) > #{roll_result.last_dice_list.join(',')} > 成功数:#{roll_result.success_num}"
  189. 6 then: 1 if roll_result.success_num > 0
  190. 1 output_text += " NRS克服!!"
  191. 1 return Result.success(output_text)
  192. else: 5 else
  193. 5 output_text += " NRS発症!! \n"
  194. end
  195. end
  196. # NRS発狂表の決定
  197. 6 dice_face = 0
  198. 6 additional = 0
  199. 6 then: 4 else: 2 if type == 0
  200. 4 else: 0 case dificulty_s
  201. when: 1 when "E"
  202. 1 dice_face = 3
  203. when: 1 when "N"
  204. 1 dice_face = 6
  205. when: 2 when "H", "U"
  206. 2 dice_face = 6
  207. 2 additional = 1
  208. end
  209. 4 type = @randomizer.roll_once(dice_face) + additional
  210. end
  211. 6 then: 2 else: 4 roll_command = "1D#{dice_face}#{additional > 0 ? '+' + additional.to_s : ''}"
  212. 6 then: 4 else: 2 output_text += "NRS発狂#{dice_face > 0 ? "(#{roll_command}) > " : ''}(#{type}) > #{translate('NinjaSlayer2.table.NRS.items')[type - 1]}"
  213. 6 return Result.failure(output_text)
  214. end
  215. # テキスト系処理
  216. # @param command [String]
  217. # @return [String, Integer]
  218. 1 def proc_text(command)
  219. 13 debug("text: #{command}")
  220. 13 else: 0 case command
  221. when RE_JUDGE_SATZ_BATZ
  222. when: 2 # サツバツ判定(d6)
  223. 2 return proc_satz_batz(Regexp.last_match[1].to_i)
  224. when RE_JUDGE_WASSHOI
  225. when: 2 # Wasshoi!判定
  226. 2 return proc_wasshoi(Regexp.last_match[1].to_i)
  227. when RE_JUDGE_WASSHOI_ENTRY
  228. when: 2 # Wasshoi!判定
  229. 2 return proc_wasshoi_entry(Regexp.last_match[1].to_i)
  230. when RE_JUDGE_NRS
  231. when: 7 # NRS判定
  232. 7 return proc_nrs(Regexp.last_match[2].to_i, Regexp.last_match[1], Regexp.last_match[3].to_i)
  233. end
  234. end
  235. 1 RE_COUNT_SATZ_BATZ = /S([1-6])?/i.freeze
  236. 1 RE_COUNT_CRITICAL = /C([1-6])?/i.freeze
  237. 1 RE_COUNT_JUDGE = /(=|!=|>=|>|<=|<)([1-6])/.freeze
  238. 1 RE_JUDGE_DICEROLL = /^(UH|[KENHU])([\d,]+)(?:\[((?:(?:S([1-6])?|C([1-6])?|(=|!=|>=|>|<=|<)([1-6]))(?:\]\[)?)+)\])?$/i.freeze
  239. 1 RE_JUDGE_SATZ_BATZ = /^SB(?:@([1-6]))?$/i.freeze
  240. 1 RE_JUDGE_WASSHOI = /^WS([1-9]|10|11|12)$/i.freeze
  241. 1 RE_JUDGE_WASSHOI_ENTRY = /^WSE(?:@([1-6]))?$/i.freeze
  242. 1 RE_JUDGE_NRS = /^NRS(?:_(E|N|H|U|UH)(\d+))?(?:@([1-7]))?$/i.freeze
  243. # 難易度の文字表現から整数値への対応
  244. 1 DIFFICULTY_SYMBOL_TO_INTEGER = {
  245. 'K' => 2,
  246. 'E' => 3,
  247. 'N' => 4,
  248. 'H' => 5,
  249. 'U' => 6,
  250. 'UH' => 6
  251. }.freeze
  252. 1 register_prefix(
  253. "UH",
  254. "[KENHU]",
  255. "SB",
  256. "WS",
  257. "WSE",
  258. "NRS"
  259. )
  260. end
  261. end
  262. end

lib/bcdice/game_system/NjslyrBattle.rb

100.0% lines covered

90.0% branches covered

21 relevant lines. 21 lines covered and 0 lines missed.
10 total branches, 9 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class NjslyrBattle < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'NjslyrBattle'
  7. # ゲームシステム名
  8. 1 NAME = 'NJSLYRBATTLE'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'にんしやすれいやあはとる'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・カラテロール
  14. 2d6<=(カラテ点)
  15. 例)2d6<=5
  16. (2D6<=5) > 2[1,1] > 2 > 成功 重点 3 溜まる
  17. INFO_MESSAGE_TEXT
  18. # ゲーム別成功度判定(2D6)
  19. 1 def result_2d6(total, _dice_total, dice_list, cmp_op, target)
  20. 9 then: 1 else: 8 return Result.nothing if target == "?"
  21. 8 then: 0 else: 8 return nil if cmp_op != :<=
  22. 8 then: 4 else: 4 result = (total <= target ? Result.success("成功") : Result.failure("失敗"))
  23. 8 result.text += juuten(dice_list)
  24. 8 return result
  25. end
  26. 1 private
  27. 1 def juuten(dice_list)
  28. 8 juuten = dice_list.count(1) + dice_list.count(6)
  29. 8 then: 3 else: 5 if dice_list[0] == dice_list[1]
  30. 3 juuten += 1
  31. end
  32. 8 then: 6 if juuten > 0
  33. 6 " 重点 #{juuten} 溜まる"
  34. else: 2 else
  35. 2 ""
  36. end
  37. end
  38. end
  39. end
  40. end

lib/bcdice/game_system/NobunagasBlackCastle.rb

98.72% lines covered

94.12% branches covered

78 relevant lines. 77 lines covered and 1 lines missed.
34 total branches, 32 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/dice_table/table'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class NobunagasBlackCastle < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'NobunagasBlackCastle'
  8. # ゲームシステム名
  9. 1 NAME = '信長の黒い城'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'のふなかのくろいしろ'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGETEXT
  14. ■判定 sDRt s: 能力値 t:目標値
  15. 例)+3DR12: 能力値+3、DR12で1d20を振って、その結果を表示(クリティカル・ファンブルも表示)
  16. ■イニシアティヴ INS
  17. 例)INS: 1d6を振って、イニシアティヴの結果を表示(PC先行を成功として表示)
  18. ■NPC能力値作成 NPCST
  19. 例)NPCST: 3d6を4回振って、各能力値とHPを表示
  20. ■各種表
  21. ・遭遇反応表(ERT)
  22. ・武器表(SWT)/その他の奇妙な武器表(OSWT)
  23. ・鎧表(ART)
  24. INFO_MESSAGETEXT
  25. 1 def initialize(command)
  26. 63 super(command)
  27. 63 @sort_add_dice = true
  28. 63 @d66_sort_type = D66SortType::NO_SORT
  29. end
  30. 1 def eval_game_system_specific_command(command)
  31. 61 resolute_action(command) || resolute_initiative(command) || roll_tables(command, TABLES) || make_npc_status(command)
  32. end
  33. 1 private
  34. 1 def result_dr(total, dice_total, target)
  35. 14 then: 1 if dice_total <= 1
  36. 1 else: 13 Result.fumble("ファンブル")
  37. 13 then: 1 elsif dice_total >= 20
  38. 1 else: 12 Result.critical("クリティカル")
  39. 12 then: 9 elsif total >= target
  40. 9 Result.success("成功")
  41. else: 3 else
  42. 3 Result.failure("失敗")
  43. end
  44. end
  45. # DR判定
  46. # @param [String] command
  47. # @return [Result]
  48. 1 def resolute_action(command)
  49. 61 m = /^([+-]?\d*)DR(\d+)$/.match(command)
  50. 61 else: 14 then: 47 return nil unless m
  51. 14 num_status = m[1].to_i
  52. 14 num_target = m[2].to_i
  53. 14 total = @randomizer.roll_once(20)
  54. 14 total_status = total.to_s + with_symbol(num_status)
  55. 14 result = result_dr(total + num_status, total, num_target)
  56. sequence = [
  57. 14 "(#{command})",
  58. total_status,
  59. total + num_status,
  60. result.text,
  61. ]
  62. 14 result.text = sequence.join(" > ")
  63. 14 return result
  64. end
  65. 1 def with_symbol(number)
  66. 30 then: 8 if number == 0
  67. 8 else: 22 return "+0"
  68. 22 then: 11 elsif number > 0
  69. 11 return "+#{number}"
  70. else: 11 else
  71. 11 return number.to_s
  72. end
  73. end
  74. # イニシアティヴ判定
  75. # @param [String] command
  76. # @return [Result]
  77. 1 def resolute_initiative(command)
  78. 47 else: 4 then: 43 unless command == "INS"
  79. 43 return nil
  80. end
  81. 4 total = @randomizer.roll_once(6)
  82. result =
  83. 4 then: 2 if total >= 4
  84. 2 Result.success("PC先行")
  85. else: 2 else
  86. 2 Result.failure("敵先行")
  87. end
  88. 4 result.text = "(#{command}) > #{total} > #{result.text}"
  89. 4 return result
  90. end
  91. # NPC能力値作成
  92. # @param [String] command
  93. # @return [String]
  94. 1 def make_npc_status(command)
  95. 4 else: 4 then: 0 unless command == "NPCST"
  96. return nil
  97. end
  98. 4 pre = @randomizer.roll_sum(3, 6)
  99. 4 agi = @randomizer.roll_sum(3, 6)
  100. 4 str = @randomizer.roll_sum(3, 6)
  101. 4 tgh = @randomizer.roll_sum(3, 6)
  102. 4 hpd = @randomizer.roll_once(8)
  103. 4 hp = hpd + calc_status(tgh)
  104. 4 then: 1 else: 3 hp = 1 if hp < 1
  105. text = [
  106. 4 "心#{with_symbol(calc_status(pre))}(#{pre})",
  107. "技#{with_symbol(calc_status(agi))}(#{agi})",
  108. "体#{with_symbol(calc_status(str))}(#{str})",
  109. "耐久#{with_symbol(calc_status(tgh))}(#{tgh})",
  110. "HP#{hp}(#{hpd})",
  111. ].join(", ")
  112. 4 return "(#{command}) > #{text}"
  113. end
  114. 1 def calc_status(st)
  115. 20 then: 4 if st <= 4
  116. 4 else: 16 return -3
  117. 16 then: 3 elsif st <= 6
  118. 3 else: 13 return -2
  119. 13 then: 2 elsif st <= 8
  120. 2 else: 11 return -1
  121. 11 then: 3 elsif st <= 12
  122. 3 else: 8 return 0
  123. 8 then: 2 elsif st <= 14
  124. 2 else: 6 return 1
  125. 6 then: 3 elsif st <= 16
  126. 3 else: 3 return 2
  127. 3 then: 3 else: 0 elsif st <= 20
  128. 3 return 3
  129. end
  130. end
  131. # 各種表
  132. TABLES = {
  133. 1 'OSWT' => DiceTable::Table.new(
  134. 'その他の奇妙な武器表',
  135. '1D10',
  136. [
  137. '六尺棒(D4)',
  138. '手槍(D4)',
  139. '弓矢(D6)',
  140. '鉄扇(D4)',
  141. '大鉞(D8)',
  142. '吹き矢(D2)+感染',
  143. '鞭(D3)',
  144. '熊手(D4)',
  145. '石つぶて(D3)',
  146. '丸太(D4)',
  147. ]
  148. ),
  149. 'SWT' => DiceTable::Table.new(
  150. '武器表',
  151. '1D12',
  152. [
  153. '尖らせた骨の杭(D3)',
  154. '竹槍(D4)',
  155. '百姓から奪った鍬(D4)',
  156. '脇差し(D4)',
  157. '手裏剣 D6本(D4)',
  158. '刀(D6)',
  159. '鎖鎌(D6)',
  160. '太刀(D8)',
  161. '種子島銃(2D6) 弾丸(心+5)発',
  162. '大槍(D8)',
  163. '爆裂弾(D4) 心+3発',
  164. '斬馬刀(D10)',
  165. ]
  166. ),
  167. 'ART' => DiceTable::Table.new(
  168. '鎧表',
  169. '1D6',
  170. [
  171. '防具は、何もない',
  172. '防具は、何もない',
  173. '部分鎧(腹巻き) -D2ダメージ',
  174. 'お貸し具足 -D3ダメージ',
  175. '武者鎧 -D4ダメージ',
  176. '大鎧 -D6ダメージ',
  177. ]
  178. ),
  179. # 無理に高度なことをしなくても、表は展開して実装しても動く
  180. 'ERT' => DiceTable::Table.new(
  181. '遭遇反応表',
  182. '2D6',
  183. [
  184. 'お前ら、殺す!',
  185. 'お前ら、殺す!',
  186. '憎悪の視線で睨んでくる。すきを見せれば、攻撃してくる。',
  187. '憎悪の視線で睨んでくる。すきを見せれば、攻撃してくる。',
  188. '憎悪の視線で睨んでくる。すきを見せれば、攻撃してくる。',
  189. '警戒はしているが、特に、戦闘は望んでいない。怒らせなければ、自分たちの目的に沿って動く。',
  190. '警戒はしているが、特に、戦闘は望んでいない。怒らせなければ、自分たちの目的に沿って動く。',
  191. '中立。何かを与えたり、取引の材料を提示したりできれば、交渉できそうだ。',
  192. '中立。何かを与えたり、取引の材料を提示したりできれば、交渉できそうだ。',
  193. '好意的に会話できそうだ。向こうも取引したがっている。',
  194. '好意的に会話できそうだ。向こうも取引したがっている。',
  195. ]
  196. ),
  197. }.freeze
  198. 1 register_prefix('[+-]?\d*DR[\d]+', 'INS', 'NPCST', TABLES.keys)
  199. end
  200. end
  201. end

lib/bcdice/game_system/Nuekagami.rb

100.0% lines covered

50.0% branches covered

19 relevant lines. 19 lines covered and 0 lines missed.
6 total branches, 3 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Nuekagami < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Nuekagami'
  7. # ゲームシステム名
  8. 1 NAME = '鵺鏡'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ぬえかかみ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・喪失表(xL)
  14.  BL:血脈、LL:生様、SL:魂魄、FL:因縁
  15. ・LR:喪失取戻表
  16. ・門通過描写表(xG)
  17.  HG:地獄門、RG:羅生門、VG:朱雀門、OG:応天門
  18. MESSAGETEXT
  19. 1 def eval_game_system_specific_command(command)
  20. 10 info = TABLES[command.upcase]
  21. 10 then: 0 else: 10 return nil if info.nil?
  22. 10 name = info[:name]
  23. 10 type = info[:type]
  24. 10 table = info[:table]
  25. text, number =
  26. 10 else: 0 case type
  27. when: 10 when '1D20'
  28. 10 get_table_by_nDx(table, 1, 20)
  29. end
  30. 10 then: 0 else: 10 return nil if text.nil?
  31. 10 return "#{name}(#{number}) > #{text}"
  32. end
  33. TABLES =
  34. {
  35. 1 "LR" => {
  36. name: "喪失取戻表",
  37. type: '1D20',
  38. table: [
  39. '鬼化。妄執かくして鬼と結実す。欠けたるところすでになし。あやかし、己の欠けたるを足せり。すなわちその身、人ならず。',
  40. '妄想。とくと見よ。何も失ってなどおらぬ。この肉この魂この身上、欠けたるところぞなし。欠けし夢を見しのみ。全て夢なり。',
  41. '鵺型。肉に内に暗雲ゆらめく。欠けたるところ漂うそれは、鶴が欠片。暖昧の境界なれば、失いしものまた戻りたるが如く。',
  42. '諦観。己が身を知る。望む愚かを知る。足掻く愚かを知る。心は折れり。望みは絶えり。諦めることで足るものもある知らむ。',
  43. '屍漁。もはやいかな所業もいとわず。されば数多の骸を漁り、ついに欠けたるを満たせり。代わりに欠けたる心、知ることぞなし。',
  44. '呪刻。あまねく呪はば、己も囚わる。己を騙る呪い、己を捕らえ絡めれば、欠けたるもまた満ちて見ゆる。',
  45. '得心。すべては己の行いの結果なれば、因果応報。それなきは不具合なれど、得心せり。もはや悩めどせんなきことなりや。',
  46. '奪取。無ければ、奪え。あな妬ましと思わば奪え。奪いて己がものとせよ。さすればたちまち、欲するところ戻れり。',
  47. '罪価。己が罪を知れり。かくあさましき罪業に比ぶれば、己が失いしもの、なんと軽きことか。さあれば、悩むるに能はず。',
  48. '代替。失へるもの、未だ失われり。されど、代わるものを得たり。二度とは失うわじ。失わばその痛みに狂い果てむ。',
  49. '受容。納得はなし。諦観はなし。されど受け入れり。欠けたるもまた己なれば、欠けるところもて満たさば、それ己ならずや。',
  50. '代行。かかる身にそれなくとも是。かく行い為すは、己が筆ならず。代わりて為す者、信ずべきあらばこそ。',
  51. '適応。心痛むる時多けれど、欠けたるにも馴れたり。もはや欠けるに不自由なし。さればそれすなわち、欠けたるに非ず',
  52. '妖賞。大妖に遇ひて、饗応す。彼の妖、大いに慶びてその身に欠けたるを与へむ。それ異様なれど、用は足れり。',
  53. '奪還。つひに奪われしもの、奪い返せり!取り戻せしそれ、再び手の内に収まりて輝けり。けしてまた手放すことあらじ。',
  54. '本懐。己の求むるを、ついに為し遂げり。もはや己が力、己が技、疑うところなし。己が有様になんぞ足らざるあるべきや。',
  55. '取得。艱難辛苦ぞありや。ついぞ果てに失いしそれ、身に修めん。ただ取り戻せしものにあらじ。新たに得たりしや。',
  56. '賜物。その欠ける様、彼の人あはれに思いて、かくなるを与え賜り。以て、満ちたる己、彼の人にまた仕えむ。',
  57. '大悟。足掻けれど足掻けれど、満ちることなし。足りざるは自然。己の姿を受け入れむ。されば欠けたるに、悩まさるるもなし。',
  58. '望月。欠けたる月が満ちるが如く。欠けたるは突然に戻れり。いかなる誠、いかなる印か、知るものはあらず。'
  59. ],
  60. },
  61. "BL" => {
  62. name: "血脈の喪失表",
  63. type: '1D20',
  64. table: [
  65. '髪の色。一夜にしてあなたの髪は白くなった。',
  66. '視力。周囲がぼんやりとしか見えない。',
  67. '所作。体の一部がまともに動かせない。',
  68. '痛み。体が痛みを感じなくなってしまった。',
  69. '容貌。顔に大きな傷や火傷を負った。',
  70. '血の気。あなたの肌は血の気を失ったままだ。',
  71. '赤い血。体を流れる血が異様な色となった。',
  72. '子を作る力。子を作る力を失った。',
  73. '器用さ。体が常に小さく震えている。',
  74. '健康。病を患った……体が衰弱している。',
  75. '寿命。あなたの寿命は残りわずかとなった。',
  76. 'ぬくもり。その体は常に冷たい……。',
  77. '片目。片目を失ってしまった……。',
  78. '片脚。片脚を切り落とされた!',
  79. '片腕。片腕を切り落とされた!',
  80. '生命。あなたの鼓動は止まって久しい。',
  81. '真の力。本来の力がほとんど発揮できない。',
  82. '肉。異様に痩せたか、体の一部が白骨化している。',
  83. '人の体。体が歪み変わり、異形と化した。',
  84. '己の体。今は他人の体を借りている。'
  85. ],
  86. },
  87. "LL" => {
  88. name: "生様の喪失表",
  89. type: '1D20',
  90. table: [
  91. '主君の寵愛。不興を買ってしまった。',
  92. '師匠。死んだか、あるいはあなたが捨てられた。',
  93. '面子。大いに恥をかいた。このままにしておけない。',
  94. '時間。今まで精魂を傾けて来たものは無駄だった。',
  95. '血縁。信じていた生まれではなかった……。',
  96. '家宝。家の宝、あるいは形見を奪われてしまった。',
  97. '恋人。死んだか、あるいは奪われた。',
  98. '運。何をやってもうまくいかない。',
  99. '財産。騙し取られたか……。あるいは使い果たした。',
  100. '名声。あなたの名声は地に落ちている……。',
  101. '居場所。居るべき場所、身分を失ってしまった……。',
  102. '地位。かつての地位は失われたのだ。',
  103. '日常。こんな世の中でも平和に暮らしていたのに。',
  104. '相棒。死んだか、あるいは裏切られた。',
  105. '仕える人。死んだか、あるいはあなたが捨てられた。',
  106. '人望。かつてあなたを讃えた人が、今やあなたを罵る。',
  107. '家族。死んだか、あるいはあなたが捨てられた。',
  108. '故郷。何者かに滅ぼされたか、あるいは自滅した。',
  109. '守るべき人。守るべき人を守れなかった……。',
  110. '自由。脅され縛られ、誰かの命令を聞くしかできない。'
  111. ],
  112. },
  113. "SL" => {
  114. name: "魂魄の喪失表",
  115. type: '1D20',
  116. table: [
  117. '誇り。誇りなど残ってはいない。',
  118. '心の余裕。今を生きるだけで精一杯。',
  119. '敬う心。己こそが全てだ。',
  120. '気力。何もやる気がおきない……。',
  121. '安眠。夜毎の悪夢に、まともに眠れない。',
  122. '信じる心。二度と人など信じるものか。',
  123. '愛。もはや誰かを愛することなどない。',
  124. '夢。前に見えていた光、目標。今は闇の中だ。',
  125. '一線。己の中の超えてはならぬ線を踏み越えた。',
  126. '信じたもの。かつて信じたのはまやかしだった。',
  127. '人の心。この世で人の心が何の役に立つ?',
  128. '瞳の光。全て虚しいものとしか見えない。',
  129. '希望。この世に何を望むというのだろう?',
  130. '自制心。己を抑えて何とする?',
  131. '涙。その目が涙を流すことはない。',
  132. '笑顔。二度と笑いなどしないだろう。',
  133. '大切な記憶。どうしてか……記憶を失っている。',
  134. '本当の自分。己を偽りすぎて、本来の己を忘れた。',
  135. '正気。今のあなたは狂気の沙汰だ!',
  136. '己の意志。あなたは誰かの人形。道具に過ぎない。'
  137. ],
  138. },
  139. "FL" => {
  140. name: "因縁表",
  141. type: '1D20',
  142. table: [
  143. '仇敵。奴は敵だ。あなたの敵だ。',
  144. '殺意。殺してやりたい。',
  145. '蔑視。口ほどにもない存在だ。',
  146. '嫉妬。なぜアイツだけが……。',
  147. '恐怖。恐ろしい。あれを怒らせてはいけない。',
  148. '目障り。邪魔だ。気に入らない。',
  149. '利用。役に立ってくれそうだな。',
  150. '玩具。せいぜい楽しませてもらおう。',
  151. '依存。あの人がいなければいけないのだ。',
  152. '欲望。お前が欲しい……。',
  153. '好敵。なかなかやるじゃないか。',
  154. '憐憎。哀れな……。',
  155. '悪友。腐れ縁。信用できないが妙に心地いい。',
  156. '畏怖。あの人には逆らえない。',
  157. '恩義。恩がある……返さなければ。',
  158. '親友。心から信じられる友だ。',
  159. '尊敬。あの人のようになりたい。',
  160. '相棒。言葉はなくとも全てが通じ合う。',
  161. '思慕。恋をしてしまった。',
  162. '主君。心の主君。身命を賭して守り仕える。'
  163. ],
  164. },
  165. "HG" => {
  166. name: "地獄門通過描写表",
  167. type: '1D20',
  168. table: [
  169. '背後見れば、地獄の門をば幻視せり。危うき次第を知りたり.',
  170. '必死に歩めり。背後に穂れし血と臓脈、こぼしたるが心地なれど。',
  171. '背後の地に深き爪痕あり。己を捕らへむとせる鬼の爪跡かと思ふ。',
  172. '劫火に焼かるる己を幻視す。汗にまみれ覚めれば、己が所業悔悟せり。',
  173. '水鏡に映る己を見て目を覚ます。彼のままなれば地獄に堕つると。',
  174. '天に鶴騒ぎたり。御身が魂晩取り逃がしたりと吃るが如く。',
  175. '足が泥淳に囚わるる幻視。引きずり込む亡者。必死に逃れ至れり。',
  176. '陰に蠢く餓鬼を見ゆ・明日は己ぞと思へば、背も震えたり。',
  177. '喪失の苦しみ、いくばくか休めり。他を思う心地ぞ生まれり。',
  178. 'いみじう悩み苦しけれど、やがてそれも馴れり。今や苦しみならず。',
  179. 'しずけき雨降らば、己が所業洗い流さるるとも、思へたり。',
  180. '汚泥が如く絡みし過ぎたる日々、わずかに離れたる心地ぞする。',
  181. '背負いし怨念ら退き薄れむ。これなるは縁がゆへか、心地ゆへか。',
  182. '内に孕むる絶望へ、連理たれと希望の芽、萌ゆる。',
  183. '生温かき風と共に、大粒の雨降れり。すわ血の雨かとも思へり。',
  184. '人と関わりて縁を見ゆ。抱ふるもの、いくらか少なくなりき。',
  185. '夢枕、あるいは白昼夢なるか。神仏現るるにすがりたり。',
  186. '劫火の中、白き手が己を引けりと幻視す。あるひは過去の縁か。',
  187. '蛙呑む蛇を見たり。あさましき業に、己をふと顧みぬ。',
  188. '心中にて、かそけき希望の糸見へり。慎重にたぐりて登らむとす。'
  189. ],
  190. },
  191. "RG" => {
  192. name: "羅生門通過描写表",
  193. type: '1D20',
  194. table: [
  195. 'むごき所業、目にせり。心強張りて、常の様にてあれず.',
  196. '人の目に、己を嗤ふ気配感じたり。怒り、悔み、恥ぞ覚えむ。',
  197. '鬼の腕より、ついに逃るるか.おぞましき震へぞ、治まりき。',
  198. '辻吹く風に、人骨散れり。たちまち無常の感、起こりて心改めたり。',
  199. '愛憎恩普、いよいよ狂ほしく。猛るまま、ただただ前へと進めり。',
  200. '飢えたる犬の如し。泥水すすりても前に進み、想い果たさむ。',
  201. '喪失、取り戻すは近し。思はず、あさましき笑みぞ浮かべり。',
  202. 'いやしき者ども、あさましき目を向くる。蔑みてまかり通らむ。',
  203. '喪失の夢繰り返すこといくたびか。もはや業苦の炎冷め、常日頃の如し。',
  204. 'あるひは己の内よりか。あやしき声あれば欲心また昂ぶらむ。',
  205. '死人を見、成仏を祈れり。心あらば、己が内にて仏も宿らむ。',
  206. 'ただただ世の無常を知れば、哀愁の情あふれ感じむ。',
  207. '路地に小さき花咲くを見ゆ。我執の心晴れたる心地せり。',
  208. '冷たき風あらば、情動わずかに治まりて、落ち着きたりけり。',
  209. '酒を飲めり。酔ひたる心地の内に、業苦も曖昧とならむ。',
  210. '見えざる大門潜りしか。境目超えたるを感ずる。いざ、知らずの地平へ。',
  211. '乞食坊主に逢ひて、恵む。これもまたいくばくの功徳なりきや。',
  212. '子供ら遊ぶを見ゆ。己が古きを思へば、思はず顔ほころびぬ。',
  213. '暗雲に包まれし都なれど今その身に、いくばくかの光差し照らしけり。',
  214. '神仏の似姿、幻視す。されば、いかな身にも信心のいくばくか起これり。'
  215. ],
  216. },
  217. "VG" => {
  218. name: "朱雀門通過描写表",
  219. type: '1D20',
  220. table: [
  221. '雷響きて、暗霊いよいよ濃ゆし。己が先を見せるるが如し。',
  222. '今一つ取り戻すは及ばぬ口惜しきに、鬼が如く唸りし。',
  223. '求めし手、届かずも絶望すれど再び、ふらふらと歩み出さむ。',
  224. 'かたときの福なるか。狐に化かさるるが如く、鹿なる泡沫の夢。',
  225. '流るる血。朱に染まる視界。されど、染まらざる中に光あり。',
  226. '己が臓腑抉るが如く。己が業、抉り捨て進まん。',
  227. '先に狐の影見ゆ。あやしけれど、迷ひながら、狐を追へり。',
  228. '大いなる境を越えたるかと思えり。未だ道半ばなれば油断許さず。',
  229. '暗雲に白鷺翔けるを見ゆ。瑞兆なれば希望もまた湧きぬ。',
  230. '内より翼の出るが心地せり。いざ思い切りて、翔ばむ。',
  231. '割れた杯より漏れたるも、重ねたる杯に。合一せば余さず受けり。',
  232. '心激しくして魚跳ねるが如く。その実も暗き水面より跳ね出たり。',
  233. '貴き牛車と行き逢はむ。幽かな香に、目ぞ覚めたる思いせり。',
  234. 'ふと口をついて歌詠めり。何者か下の句継ぎて、心合わせむ。',
  235. '知らずの人より、送られし歌あり。返歌いかがせむかと思ひたり。',
  236. '鳥の巣立つを見たり。己もまた、新たな道歩むべきぞと心せり。',
  237. '暗雲貫きて、空に月あり。天より見らるる心地して、行い正せり。',
  238. '目的近づけど、心重し。胸痛みて、いみじう哀し。',
  239. '不意に仏心起こりて、万物慈みの念おぼえたり。',
  240. '頭上より何者かの楽の音、饗けり。その身、祝はるる心地せり。'
  241. ],
  242. },
  243. "OG" => {
  244. name: "応天門通過描写表",
  245. type: '1D20',
  246. table: [
  247. '光捕らへど暗し。新たなる地獄の門に落つる己を知りたり。',
  248. '求めしもの得たり。されど、なにものか失いし心地ぞせる……。',
  249. '狐鴫きて自覚むる。全て一夜の夢の如し。痛みもまたしかり。',
  250. 'なにゆへか、涙こぼるる。ただ涙こぼれ、業苦もまた流れむ。',
  251. '人想ひて、未練生まるる。己が幸求めれば、死を畏れむ。',
  252. '打ち返す波の音聞く。遥か遠く、旅立ちたむと念、生じたり。',
  253. '実る稲田を幻視す。もはや都の有様、人住む地に非ずと思へり。',
  254. '取り戻したるに、ただただ歓喜す。もはや周りの様も感ぜず。',
  255. 'あまたの人の目、御身見てざわめくを感ず。優越の心地あり。',
  256. 'かけがへなきもの、見つけたり。今はただ、そを喜ぶのみなれば。',
  257. '天盤にて星巡り、時満ちて、方合へり。なればその身にも幸ありむ。',
  258. '幾年月ぞ、剥那の如し。思ふれば囚わる檻も、無きかと見ゆ。',
  259. '天より鵺退きて、日の光差す。浴びる中、魂魄またぬくもりを覚えり。',
  260. '風流、解する心あらば天地自然もまた並び、自らその内に合一せむ。',
  261. 'いかにせで、己の在り様を責むるや。己は己なれが、気に負うに値せず。',
  262. 'あまねく世のことども、遠く鈍く思ひて心安らかなる境地に至れり。',
  263. '天遠く光差せば、淡き虹も浮かべり。何処かへ渡す橋とも見ゆ。',
  264. '天より一輪の花舞い降りて、御身の手に落つ。心また花咲けり。',
  265. '鵺の内に竜神舞へり。風雨激しく、身濡らせど、心清々し。',
  266. '都の暗雲、晴れたる日も稀にあり。なんぞ魂魄晴るる日なしや。'
  267. ],
  268. },
  269. }.freeze
  270. 1 register_prefix(TABLES.keys)
  271. end
  272. end
  273. end

lib/bcdice/game_system/OneWayHeroics.rb

96.83% lines covered

92.86% branches covered

63 relevant lines. 61 lines covered and 2 lines missed.
28 total branches, 26 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/one_way_heroics/tables"
  3. 1 require "bcdice/game_system/one_way_heroics/dungeon_table"
  4. 1 require "bcdice/game_system/one_way_heroics/random_event_table"
  5. 1 module BCDice
  6. 1 module GameSystem
  7. 1 class OneWayHeroics < Base
  8. # ゲームシステムの識別子
  9. 1 ID = 'OneWayHeroics'
  10. # ゲームシステム名
  11. 1 NAME = '片道勇者TRPG'
  12. # ゲームシステム名の読みがな
  13. 1 SORT_KEY = 'かたみちゆうしやTRPG'
  14. # ダイスボットの使い方
  15. 1 HELP_MESSAGE = <<~MESSAGETEXT
  16. ・判定 aJDx+y,z
  17.  a:ダイス数(省略時2個)、x:能力値、
  18.  y:修正値(省略可。「+」のみなら+1)、z:目標値(省略可)
  19.  例1)JD2+1,8 or JD2+,8 :能力値2、修正+1、目標値8
  20.  例2)JD3,10 能力値3、修正なし、目標値10
  21.  例3)3JD4+ ダイス3個から2個選択、能力値4、修正なし、目標値なし
  22. ・ファンブル表 FT/魔王追撃表 DC/進行ルート表 PR/会話テーマ表 TT
  23. 逃走判定表 EC/ランダムNPC特徴表 RNPC/偵察表 SCT
  24. 施設表 FCLT/施設表プラス FCLTP/希少動物表 RANI/王特徴表プラス KNGFTP
  25. 野外遭遇表 OUTENC/野外遭遇表プラス OUTENCP
  26. モンスター特徴表 MONFT/モンスター特徴表プラス MONFTP
  27. ドロップアイテム表 DROP/ドロップアイテム表プラス DROPP
  28. 武器ドロップ表 DROPWP/武器ドロップ表2 DROPWP2
  29. 防具ドロップ表 DROPAR/防具ドロップ表2 DROPAR2
  30. 聖武具ドロップ表 DROPHW/聖武具ドロップ表プラス DROPHWP
  31. 食品ドロップ表 DROPFD/食品ドロップ表2 DROPFD2
  32. 巻物ドロップ表 DROPSC/巻物ドロップ表2 DROPSC2
  33. その他ドロップ表 DROPOT/その他 ドロップ表2 DROPOT2
  34. 薬品ドロップ表プラス DROPDRP/珍しい箱ドロップ表2 DROPRAREBOX2
  35. ・ランダムイベント表 RETx(x:現在の日数)、ランダムイベント表プラス RETPx
  36.  例)RET3、RETP4
  37. ・ダンジョン表 DNGNx(x:現在の日数)、ダンジョン表プラス DNGNPx
  38.  例)DNGN3、DNGNP4
  39. MESSAGETEXT
  40. 1 def initialize(command)
  41. 76 super(command)
  42. 76 @d66_sort_type = D66SortType::ASC
  43. end
  44. 1 def eval_game_system_specific_command(command)
  45. 74 case command
  46. when: 10 when /^RET(\d+)$/
  47. 10 day = Regexp.last_match(1).to_i
  48. 10 RANDOM_EVENT_TABLE.roll_with_day(day, @randomizer)
  49. when: 9 when /^RETP(\d+)$/
  50. 9 day = Regexp.last_match(1).to_i
  51. 9 RANDOM_EVENT_TABLE_PLUS.roll_with_day(day, @randomizer)
  52. when: 1 when /^DNGN(\d+)$/
  53. 1 day = Regexp.last_match(1).to_i
  54. 1 DUNGEON_TABLE.roll_with_day(day, @randomizer)
  55. when: 0 when /^DNGNP(\d+)$/
  56. day = Regexp.last_match(1).to_i
  57. DUNGEON_TABLE_PLUS.roll_with_day(day, @randomizer)
  58. when: 16 when /^\d*JD/
  59. 16 getRollDiceCommandResult(command)
  60. else: 38 else
  61. 38 roll_tables(command, TABLES)
  62. end
  63. end
  64. 1 def getRollDiceCommandResult(command)
  65. 16 else: 16 then: 0 return nil unless command =~ /^(\d*)JD(\d*)(\+(\d*))?(,(\d+))?$/
  66. 16 diceCount = Regexp.last_match(1)
  67. 16 then: 8 else: 8 diceCount = 2 if diceCount.empty?
  68. 16 diceCount = diceCount.to_i
  69. 16 then: 1 else: 15 return nil if diceCount < 2
  70. 15 ability = Regexp.last_match(2).to_i
  71. 15 target = Regexp.last_match(6)
  72. 15 else: 4 then: 11 target = target.to_i unless target.nil?
  73. 15 modifyText = Regexp.last_match(3) || ""
  74. 15 then: 8 else: 7 modifyText = "+1" if modifyText == "+"
  75. 15 modifyValue = modifyText.to_i
  76. 15 dice, diceText = rollJudgeDice(diceCount)
  77. 15 total = dice + ability + modifyValue
  78. 15 text = command.to_s
  79. 15 text += " > #{diceCount}D6[#{diceText}]+#{ability}#{modifyText}"
  80. 15 text += " > #{total}"
  81. 15 result = getJudgeReusltText(dice, total, target)
  82. 15 else: 3 then: 12 text += " > #{result}" unless result.empty?
  83. 15 return text
  84. end
  85. 1 def rollJudgeDice(diceCount)
  86. 15 diceList = @randomizer.roll_barabara(diceCount, 6)
  87. 15 dice = diceList.sum()
  88. 15 diceText = diceList.join(",")
  89. 15 then: 8 else: 7 if diceCount == 2
  90. 8 return dice, diceText
  91. end
  92. 7 diceList.sort!
  93. 7 diceList.reverse!
  94. 7 total = diceList[0] + diceList[1]
  95. 7 text = "#{diceText}→#{diceList[0]},#{diceList[1]}"
  96. 7 return total, text
  97. end
  98. 1 def getJudgeReusltText(dice, total, target)
  99. 15 then: 3 else: 12 return "ファンブル" if dice == 2
  100. 12 then: 2 else: 10 return "スペシャル" if dice == 12
  101. 10 then: 3 else: 7 return "" if target.nil?
  102. 7 then: 5 else: 2 return "成功" if total >= target
  103. 2 return "失敗"
  104. end
  105. 1 register_prefix('\d*JD', 'RETP?', 'DNGNP?', TABLES.keys)
  106. end
  107. end
  108. end

lib/bcdice/game_system/OracleEngine.rb

95.97% lines covered

87.93% branches covered

124 relevant lines. 119 lines covered and 5 lines missed.
58 total branches, 51 branches covered and 7 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/format'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class OracleEngine < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'OracleEngine'
  8. # ゲームシステム名
  9. 1 NAME = 'オラクルエンジン'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'おらくるえんしん'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<MESSAGETEXT
  14. ・クラッチロール (xCL+y>=z)
  15. ダイスをx個振り、1個以上目標シフトzに到達したか判定します。修正yは全てのダイスにかかります。
  16. 成功した時は目標シフトを、失敗した時はダイスの最大値-1シフトを返します
  17. zが指定されないときは、ダイスをx個を振り、それに修正yしたものを返します。
  18. 通常、最低シフトは1、最大シフトは6です。目標シフトもそろえられます。
  19. また、CLの後に7を入れ、(xCL7+y>=z)と入力すると最大シフトが7になります。
  20. ・判定 (xR6+y@c#f$b>=z)
  21. ダイスをx個振り、大きいもの2つだけを見て達成値を算出し、成否を判定します。修正yは達成値にかかります。
  22. ダイスブレイクとしてbを、クリティカル値としてcを、ファンブル値としてfを指定できます。
  23. それぞれ指定されない時、0,12,2になります。
  24. クリティカル値の上限はなし、下限は2。ファンブル値の上限は12、下限は0。
  25. zが指定されないとき、達成値の算出のみ行います。
  26. ・ダメージロールのダイスブレイク (xD6+y$b)
  27. ダイスをx個振り、合計値を出します。修正yは合計値にかかります。
  28. ダイスブレイクとしてbを指定します。合計値は0未満になりません。
  29. MESSAGETEXT
  30. # ダイスボットで使用するコマンドを配列で列挙する
  31. 1 register_prefix('\d+CL', '\d+R6', '\d+D6.*\$[\+\-]?\d+')
  32. 1 def initialize(command)
  33. 116 super(command)
  34. 116 @sort_add_dice = true
  35. 116 @sort_barabara_dice = true
  36. end
  37. 1 def eval_game_system_specific_command(command)
  38. 116 else: 0 case command
  39. when: 56 when /\d+CL.*/i
  40. 56 clutch_roll(command)
  41. when: 11 when /\d+D6.*\$[+-]?\d.*/
  42. 11 damage_roll(command)
  43. when: 49 when /\d+R6/
  44. 49 r_roll(command)
  45. end
  46. end
  47. # クラッチロール
  48. 1 def clutch_roll(string)
  49. 56 debug("clutch_roll begin", string)
  50. 56 parser = Command::Parser.new(/\d+CL[67]?/, round_type: round_type)
  51. .restrict_cmp_op_to(nil, :>=)
  52. 56 @cmd = parser.parse(string)
  53. 56 else: 56 then: 0 unless @cmd
  54. return nil
  55. end
  56. 56 @times, @max_shift = @cmd.command.split("CL").map(&:to_i)
  57. 56 @max_shift ||= 6
  58. 56 then: 31 else: 25 @cmd.target_number = clamp(@cmd.target_number, 1, @max_shift) if @cmd.cmp_op
  59. 56 then: 0 else: 56 if @times == 0
  60. return nil
  61. end
  62. 248 dice_list = @randomizer.roll_barabara(@times, 6).map { |x| clamp(x + @cmd.modify_number, 1, @max_shift) }.sort
  63. sequence = [
  64. 56 expr_clutch(),
  65. "[#{dice_list.join(', ')}]",
  66. result_clutch(dice_list.last)
  67. ]
  68. 56 return sequence.join(' > ')
  69. end
  70. 1 def expr_clutch()
  71. 56 then: 16 else: 40 max_shift = @max_shift == 7 ? 7 : nil
  72. 56 cmp_op = Format.comparison_operator(@cmd.cmp_op)
  73. 56 modify_number = Format.modifier(@cmd.modify_number)
  74. 56 "(#{@times}CL#{max_shift}#{modify_number}#{cmp_op}#{@cmd.target_number})"
  75. end
  76. 1 def result_clutch(after_shift)
  77. 56 then: 25 if @cmd.cmp_op != :>=
  78. 25 else: 31 "シフト#{after_shift}"
  79. 31 then: 21 elsif after_shift >= @cmd.target_number
  80. 21 "成功 シフト#{@cmd.target_number}"
  81. else: 10 else
  82. 10 after_shift -= 1
  83. 10 then: 1 else: 9 after_shift = 1 if after_shift < 1
  84. 10 "失敗 シフト#{after_shift}"
  85. end
  86. end
  87. 1 def clamp(i, min, max)
  88. 272 then: 19 if i < min
  89. 19 else: 253 min
  90. 253 then: 19 elsif i > max
  91. 19 max
  92. else: 234 else
  93. 234 i
  94. end
  95. end
  96. # 判定
  97. 1 def r_roll(string)
  98. 49 parser = Command::Parser.new(/\d+R6/, round_type: round_type)
  99. .restrict_cmp_op_to(nil, :>=)
  100. .enable_critical
  101. .enable_fumble
  102. .enable_dollar
  103. 49 @cmd = parser.parse(string)
  104. 49 else: 49 then: 0 unless @cmd
  105. return nil
  106. end
  107. 49 @times = @cmd.command.to_i
  108. 49 then: 0 else: 49 if @times == 0
  109. return nil
  110. end
  111. 49 @critical = normalize_critical(@cmd.critical || 12, string)
  112. 49 @fumble = normalize_fumble(@cmd.fumble || 2, string)
  113. 49 @break = (@cmd.dollar || 0).abs
  114. 49 dice_list = @randomizer.roll_barabara(@times, 6).sort
  115. 49 dice_broken = dice_list.pop(@break)
  116. # ブレイク後のダイスから最大値2つの合計がダイスの値
  117. 49 dice_total = dice_list.dup.pop(2).inject(0, :+)
  118. 49 total = dice_total + @cmd.modify_number
  119. sequence = [
  120. 49 expr_r(),
  121. dice_result_r(dice_total, dice_list, dice_broken),
  122. result_r(dice_total, total)
  123. ]
  124. 49 return sequence.join(' > ')
  125. end
  126. 1 def expr_r()
  127. 49 modify_number = Format.modifier(@cmd.modify_number)
  128. 49 then: 40 else: 9 critical = @critical == 12 ? "" : "c[#{@critical}]"
  129. 49 then: 38 else: 11 fumble = @fumble == 2 ? "" : "f[#{@fumble}]"
  130. 49 then: 40 else: 9 brak = @break == 0 ? "" : "b[#{@break}]"
  131. 49 cmp_op = Format.comparison_operator(@cmd.cmp_op)
  132. 49 "(#{@times}R6#{modify_number}#{critical}#{fumble}#{brak}#{cmp_op}#{@cmd.target_number})"
  133. end
  134. 1 def dice_result_r(dice_total, dice_list, break_list)
  135. 49 modify_number_text = Format.modifier(@cmd.modify_number)
  136. 49 then: 40 if break_list.empty?
  137. 40 "#{dice_total}[#{dice_list.join(', ')}]#{modify_number_text}"
  138. else: 9 else
  139. 9 "#{dice_total}[#{dice_list.join(', ')}]×[#{break_list.join(', ')}]#{modify_number_text}"
  140. end
  141. end
  142. 1 def result_r(dice_total, total)
  143. 49 then: 13 if dice_total <= @fumble
  144. 13 else: 36 "ファンブル!"
  145. 36 then: 9 elsif dice_total >= @critical
  146. 9 else: 27 "クリティカル!"
  147. 27 then: 4 elsif @cmd.cmp_op == :>=
  148. 4 then: 2 if total >= @cmd.target_number
  149. 2 "#{total} 成功"
  150. else: 2 else
  151. 2 "#{total} 失敗"
  152. end
  153. else: 23 else
  154. 23 total.to_s
  155. end
  156. end
  157. 1 def normalize_critical(critical, string)
  158. 49 then: 4 else: 45 if /@[+-]/.match(string)
  159. 4 critical = 12 + critical
  160. end
  161. 49 then: 2 else: 47 if critical < 2
  162. 2 critical = 2
  163. end
  164. 49 return critical
  165. end
  166. 1 def normalize_fumble(fumble, string)
  167. 49 then: 5 else: 44 if /#[+-]/.match(string)
  168. 5 fumble = 2 + fumble
  169. end
  170. 49 return clamp(fumble, 0, 12)
  171. end
  172. # ダメージロール
  173. 1 def damage_roll(string)
  174. 11 parser = Command::Parser.new(/\d+D6/, round_type: round_type)
  175. .restrict_cmp_op_to(nil)
  176. .enable_dollar
  177. 11 @cmd = parser.parse(string)
  178. 11 else: 11 then: 0 return nil unless @cmd
  179. 11 @times = @cmd.command.to_i
  180. 11 @break = (@cmd.dollar || 0).abs
  181. 11 then: 0 else: 11 if @times == 0
  182. return nil
  183. end
  184. 11 dice_list = @randomizer.roll_barabara(@times, 6).sort
  185. 11 dice_broken = dice_list.pop(@break)
  186. 11 total_n = dice_list.inject(0, :+) + @cmd.modify_number
  187. 11 then: 1 else: 10 total_n = 0 if total_n < 0
  188. sequence = [
  189. 11 expr_damage(),
  190. result_damage(dice_list, dice_broken),
  191. total_n
  192. ]
  193. 11 return sequence.join(' > ')
  194. end
  195. 1 def expr_damage()
  196. 11 modify_number = Format.modifier(@cmd.modify_number)
  197. 11 then: 1 else: 10 brak = @break == 0 ? "" : "b[#{@break}]"
  198. 11 "(#{@times}D6#{modify_number}#{brak})"
  199. end
  200. 1 def result_damage(dice_list, break_list)
  201. 11 dice_total = dice_list.inject(0, :+)
  202. 11 modify_number_text = Format.modifier(@cmd.modify_number)
  203. 11 then: 1 if break_list.empty?
  204. 1 "#{dice_total}[#{dice_list.join(', ')}]#{modify_number_text}"
  205. else: 10 else
  206. 10 "#{dice_total}[#{dice_list.join(', ')}]×[#{break_list.join(', ')}]#{modify_number_text}"
  207. end
  208. end
  209. end
  210. end
  211. end

lib/bcdice/game_system/OrgaRain.rb

100.0% lines covered

83.33% branches covered

31 relevant lines. 31 lines covered and 0 lines missed.
6 total branches, 5 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class OrgaRain < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'OrgaRain'
  7. # ゲームシステム名
  8. 1 NAME = '在りて遍くオルガレイン'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ありてあまねくおるかれいん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. 判定:[n]OR(count)
  14. []内のコマンドは省略可能。
  15. 「n」でダイス数を指定。省略時は「1」。
  16. (count)で命数を指定。「3111」のように記述。最大6つ。順不同可。
  17. 【書式例】
  18. ・5OR6042 → 5dで命数「0,2,4,6」の判定
  19. ・6OR33333 → 6dで命数「3,3,3,3,3」の判定。
  20. MESSAGETEXT
  21. 1 def initialize(command)
  22. 7 super(command)
  23. 7 @sort_add_dice = true # ダイスのソート有
  24. end
  25. 1 register_prefix(
  26. '(\d+)?OR(\d{0,6})?'
  27. )
  28. 1 def eval_game_system_specific_command(command)
  29. 7 m = command.match(/(\d+)?OR(\d{0,6})$/i)
  30. 7 else: 7 then: 0 return nil unless m
  31. 7 dice_count = (m[1] || 1).to_i
  32. 7 count_no = (m[2] || "").each_char.map(&:to_i).sort
  33. 7 return check_roll(dice_count, count_no)
  34. end
  35. 1 def check_roll(dice_count, count_no)
  36. 7 dice_array = @randomizer.roll_barabara(dice_count, 10).sort
  37. 7 dice_text = dice_array.join(',')
  38. 7 result_array = []
  39. 7 success = 0
  40. 34 then: 1 else: 26 dice_array.map { |x| x == 10 ? 0 : x }.each do |i|
  41. 27 multiple = count_no.count(i)
  42. 27 then: 11 if multiple > 0
  43. 11 result_array.push("#{i}(x#{multiple})")
  44. 11 success += multiple
  45. else: 16 else
  46. 16 result_array.push("×")
  47. end
  48. end
  49. 7 count_text = count_no.join(',')
  50. 7 result_text = result_array.join(',')
  51. 7 return "#{dice_count}D10(命数:#{count_text}) > #{dice_text} > #{result_text} > 成功数:#{success}"
  52. end
  53. end
  54. end
  55. end

lib/bcdice/game_system/Oukahoushin3rd.rb

100.0% lines covered

50.0% branches covered

18 relevant lines. 18 lines covered and 0 lines missed.
2 total branches, 1 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Oukahoushin3rd < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Oukahoushin3rd'
  7. # ゲームシステム名
  8. 1 NAME = '央華封神RPG 第三版'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'おうかほうしんRPG3'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・各種表
  14.  ・能力値判定裏成功表(NHT)
  15.  ・武器攻撃裏成功表(BKT)
  16.  ・受け・回避裏成功表(UKT)
  17.  ・仙術行使裏成功表(SKT)
  18.  ・仙術抵抗裏成功表(STT)
  19.  ・精神値ダメージ悪影響表(SDT)
  20.  ・狂気表(KKT)
  21. INFO_MESSAGE_TEXT
  22. 1 def eval_game_system_specific_command(command)
  23. 15 chosen = roll_tables(command, TABLES)
  24. 15 return replace_dice_notation(chosen)
  25. end
  26. 1 private
  27. 1 def replace_dice_notation(text)
  28. 15 then: 15 else: 0 text&.gsub(/(\d+)D(\d+)/) do |matched|
  29. 3 times, sides = matched.split("D").map(&:to_i)
  30. 3 value = @randomizer.roll_sum(times, sides)
  31. 3 "#{matched}(=>#{value})"
  32. end
  33. end
  34. TABLES = {
  35. 1 "BKT" => DiceTable::Table.new(
  36. "武器攻撃裏成功表",
  37. "2D6",
  38. [
  39. "1ポイント清徳値が低下。連続攻撃が行える。この場合の連続攻撃においては、命中判定のサイコロは常にひっくり返して用いるが、2撃目以降はこの表は使わない。",
  40. "敵に叩きつけると同時に武器が破損。素手や身体に備わった武器(爪、牙など)で攻撃をしていた場合には、自身にも1D6(のみ)ダメージ。",
  41. "効果的命中。ダメージに1D6加算。ただし極度に疲労するため、精神値に1D6点ダメージを受ける。(2ゾロ)1ポイント仙骨が上昇、体力または機敏(攻撃を行った者が選択する)が1ポイント低下。",
  42. "ふつうの命中。",
  43. "不完全な命中、ダメージは半分。(3ゾロ)1ポイント仙骨が低下。",
  44. "ふつうの命中。",
  45. "体力または機敏(攻撃を行った者が選択する)が1D6日間、1ポイント上昇。(4ゾロ)能力値の上昇は永遠。",
  46. "ふつうの命中。",
  47. "体力または機敏(攻撃を行った者が選択する)が1D6日間、1ポイント低下。(5ゾロ)能力値の低下は永遠。",
  48. "呼吸を乱す、数瞬間(1D6ラウンド)は仙術を使用できない。",
  49. "1ポイント清徳値が低下。体力または機敏(攻撃を行った者が選択する)が1ポイント上昇。"
  50. ]
  51. ),
  52. "KKT" => DiceTable::Table.new(
  53. "狂気表",
  54. "2D6",
  55. [
  56. "心神喪失、生ける屍。",
  57. "被害妄想。仲間も含め、他者は全て自分を傷つけようとしていると思いこむ。行動はゲームマスターが管理。",
  58. "重度の不安症。失敗を恐れるあまり、次ラウンドは行動不可。それ以降も、2ラウンドに1回しか行動できない(自動武器や使役獣への命令なども)。\\n「次のラウンドに行動できない」状態では、「割り込み」は行えない。",
  59. "重度の依存症。自分で行動を決められず、仲間に決めてもらわなければならない。",
  60. "二重人格。二つ目の人格は狂気。新たに狂気表(KKT)で決定(再度二重人格が出た場合は、振りなおす)。狂気表を使った直後は、この二つ目の人格。\\n1日以上、二重人格が持続している場合、その間に精神値ダメージを受けるたびに、その直後に1Dを振らねばならない。1が出たらこの狂気が顔を出す。\\n二つ目の人格が顔を出している時間は、1Dで決定する(1~3:短時間、4~5:半日、6:1日)。",
  61. "軽度の依存症。仲間の承認がなければ、思いついた行動を実行できない。",
  62. "軽度の偏執狂。ある行為や物品などに異常な執着を示す。ただし、行動に大きな影響は与えない。具体的な内容は、ゲームマスターとプレイヤーの相談で決定。",
  63. "重度の偏執狂。行動に重大な影響を与える。具体的内容は、ゲームマスターが決定。",
  64. "恐怖症。あるものに対して恐怖。対象からは、ひたすら逃亡しようとする。また、対象に遭遇するたびに、難易度10で意志の能力値判定を行わねばならず、失敗したら1Dの精神値ダメージを受ける。恐怖の対象は、ゲームマスターが決定。",
  65. "狂暴化。仲間も含め、他者はすべて敵とみなし、傷つけようとする。行動はゲームマスターが管理。",
  66. "錯乱。行動はゲームマスターが「なるべくでたらめになるように」決定する。"
  67. ]
  68. ),
  69. "NHT" => DiceTable::Table.new(
  70. "能力値判定裏成功表",
  71. "2D6",
  72. [
  73. "1ポイント清徳値が低下。変な癖が身についてしまう。",
  74. "やりすぎ。過剰な成功をしたり、よけいなことまでして災いが起こりうる。",
  75. "「気」の爆発。大成功。ただし極度に疲労するため、精神値に1D6点ダメージを受ける。(2ゾロ)1ポイント仙骨が上昇、使用した能力値が1ポイント低下。",
  76. "ふつうの成功。",
  77. "不完全な成功、数値的効果は半分ほどに見積もる。(3ゾロ)1ポイント仙骨が低下。",
  78. "ふつうの成功。",
  79. "使用した能力値が1D6日間、1ポイント上昇。(4ゾロ)能力値の上昇は永遠。",
  80. "ふつうの成功。",
  81. "使用した能力値が1D6日間、1ポイント低下。(5ゾロ)能力値の低下は永遠。",
  82. "呼吸を乱す、数瞬間(1D6ラウンド)は仙術を使用できない。",
  83. "1ポイント清徳値が低下。使用した能力値が1ポイント上昇。"
  84. ]
  85. ),
  86. "SDT" => DiceTable::Table.new(
  87. "精神値ダメージ悪影響表",
  88. "1D6",
  89. [
  90. "一瞬の放心。直後の判定は自動的に失敗。精神値を1D6×最大値の10%回復。",
  91. "一瞬の放心。直後の判定は自動的に失敗。精神値を1D6×最大値の10%回復。",
  92. "一瞬の放心。直後の判定は自動的に失敗。精神値を1D6×最大値の10%回復。",
  93. "放心状態。強制され、自動失敗するまで、自発的行動不可。精神値を(1D6+2)×最大値の10%回復。",
  94. "精神異常(具体的内容は狂気表(KKT)で決定)。短時間のみ。精神値を(1D6+4)×最大値の10%回復。",
  95. "精神異常(具体的内容は狂気表(KKT)で決定)。期間は1D6を振って決定(1~3:1日、4~5:99日間、6:永遠)。精神値を最大値まで回復。"
  96. ]
  97. ),
  98. "SKT" => DiceTable::Table.new(
  99. "仙術行使裏成功表",
  100. "2D6",
  101. [
  102. "1ポイント清徳値が低下。1ポイント仙骨が上昇。",
  103. "術の効果は術者にも解除不能になる。精神値に1点ダメージを受ける。",
  104. "「気」の暴走。効果3倍。ただし極度に疲労するため、精神値に1D6点ダメージを受ける。(2ゾロ)術者は1D6日間、仙術が使用不能になる。1ポイント仙骨が上昇。",
  105. "術が敵にかけたものの場合、仲間の1人を巻きこむ。精神値に1点ダメージを受ける。",
  106. "不完全な成功、効果半分。(3ゾロ)持続時間のある術の場合、術者がひたすら精神集中していない限り、術はすぐに解除される。",
  107. "ふつうの成功。",
  108. "1ポイント清徳値が低下。(4ゾロ)仙骨以外のいずれかの能力値(術者選択)が1D6日間、1ポイント上昇。",
  109. "術が味方もしくは自分にかけたものの場合、敵の1人にも同じようにかかる。精神値に1点ダメージを受ける。",
  110. "仙骨以外のいずれかの能力値(術者選択)が1D6日間、1ポイント低下。(5ゾロ)能力値の低下は永遠。",
  111. "1D3ポイント清徳値が低下。",
  112. "1D6ポイント清徳値が低下。仙骨以外のいずれかの能力値(術者選択)が1ポイント上昇。"
  113. ]
  114. ),
  115. "STT" => DiceTable::Table.new(
  116. "仙術抵抗裏成功表",
  117. "2D6",
  118. [
  119. "1ポイント清徳値が低下。",
  120. "そらされた術の効果が味方に及ぶ。味方の誰にそらされたかは、この表を使ったものが選ぶ。集団攻撃仙術の場合、抵抗に成功したものの中から選ぶこと。ほかの誰も成功に抵抗していなかったときは、ふつうの抵抗成功として扱う。精神値に1点ダメージを受ける。",
  121. "仙術をかけた敵にその効果が及ぼされる。敵自身はそれに対して、抵抗を試みることができる。(2ゾロ)1ポイント仙骨が上昇。1ポイント知覚が低下。",
  122. "ふつうの抵抗成功。",
  123. "不完全な抵抗、ふつうの半分の効果を受ける。(3ゾロ)1ポイント仙骨が低下。",
  124. "ふつうの抵抗成功。",
  125. "仙骨または知覚(仙術に抵抗した者が選択する)が1D6日間、1ポイント上昇。(4ゾロ)能力値の上昇は永遠。",
  126. "ふつうの抵抗成功。",
  127. "仙骨または知覚(仙術に抵抗した者が選択する)が1D6日間、1ポイント低下。(5ゾロ)能力値の低下は永遠。",
  128. "呼吸を乱す、数瞬間(1D6ラウンド)は仙術を使用できない。",
  129. "1ポイント清徳値が低下。仙骨または知覚(仙術に抵抗した者が選択する)が1ポイント上昇。"
  130. ]
  131. ),
  132. "UKT" => DiceTable::Table.new(
  133. "受け・回避裏成功表",
  134. "2D6",
  135. [
  136. "1ポイント清徳値が低下。",
  137. "転倒する(空を飛んでいるものは落下。乗騎などに乗っていたら転落)。精神値に1点ダメージを受ける。",
  138. "相手のバランスを崩すのに成功。攻撃を行った敵が転倒(空を飛んでいるものは落下。乗騎などに乗っていたら転落)。(2ゾロ)1ポイント仙骨が上昇、機敏または知覚(攻撃を防御した者が選択する)が1ポイント低下。",
  139. "ふつうの防御成功。",
  140. "不完全な防御、通常の半分のダメージを受ける。しかし敵が連続攻撃を行うことは出来ない。攻撃者が裏成功攻撃であってもその反動は決めない。(3ゾロ)1ポイント仙骨が低下。",
  141. "ふつうの防御成功。",
  142. "機敏または知覚(攻撃を防御した者が選択する)が1D6日間、1ポイント上昇。(4ゾロ)能力値の上昇は永遠。",
  143. "ふつうの防御成功。",
  144. "機敏または知覚(攻撃を防御した者が選択する)が1D6日間、1ポイント低下。(5ゾロ)能力値の低下は永遠。",
  145. "呼吸を乱す、数瞬間(1D6ラウンド)は仙術を使用できない。",
  146. "1ポイント清徳値が低下。機敏または知覚(攻撃を防御した者が選択する)が1ポイント上昇。"
  147. ]
  148. ),
  149. }.freeze
  150. 1 register_prefix(TABLES.keys)
  151. end
  152. end
  153. end

lib/bcdice/game_system/Paradiso.rb

61.9% lines covered

36.63% branches covered

168 relevant lines. 104 lines covered and 64 lines missed.
101 total branches, 37 branches covered and 64 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Paradiso < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Paradiso'
  7. # ゲームシステム名
  8. 1 NAME = 'チェレステ色のパラディーゾ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ちえれすていろのはらていいそ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ◆判定 (nCPt[f]@c)、(nD20<=t[f]@c) n:ダイス数(省略時:1) t:目標値(省略時:14) f:絶不調の追加ファンブル値 c:人機一体の追加クリティカル値
  14.  例)CP12 CP(13+1) 3CP12[18,19]@7
  15. ◆各種表
  16.  ・ラジオ・マリエッタ表 RMT
  17.  ・移動表 TOT
  18.  ・探索表 EXT
  19.  ・補給表 SUT
  20. ◆ダメージチェック (DCa[20,30]) a:【攻撃力】、[20]:20mm機銃追加、[30]:30mmガンポッド追加
  21.  例)DC4:【攻撃力】4でダメージチェック DC5[20]:【攻撃力】5でダメージチェック、うち1つは20mm機銃 DC5[20,30]:【攻撃力】5でダメージチェック、うち1つは20mm機銃、うち1つは30mmガンポッド
  22. MESSAGETEXT
  23. 1 register_prefix('\d*D20<=', '\d*CP', 'RMT', 'TOT', 'EXT', 'SUT', 'DC')
  24. 1 def eval_game_system_specific_command(command) # ダイスロールコマンド
  25. # 通常判定部分をgetJudgeResultコマンドに切り分け
  26. 12 result = getJudgeResult(command)
  27. 12 else: 5 then: 7 return result unless result.nil?
  28. # ダメージチェック部分をgetDamageResultコマンドに切り分け
  29. 5 result = getDamageResult(command)
  30. 5 else: 2 then: 3 return result unless result.nil?
  31. # テーブル
  32. 2 else: 0 case command.upcase # 大文字にしてチェックする
  33. when: 1 when 'RMT'
  34. 1 result = get_radiomarietta_table
  35. when: 0 when 'TOT'
  36. result = get_takeoff_table
  37. when: 0 when 'EXT'
  38. result = get_exploration_table
  39. when: 1 when 'SUT'
  40. 1 result = get_flightsupply_table
  41. end
  42. 2 else: 0 then: 2 return result unless result.nil?
  43. end
  44. # 通常判定
  45. 1 def getJudgeResult(command)
  46. 12 case command
  47. when: 2 when /^(\d+)?D20<=(\d+)?(\[(\d+)(,(\d+))?\])?(@(\d+))?$/i
  48. 2 number = (Regexp.last_match(1) || 1).to_i # ダイス数。省略時は1
  49. 2 target = (Regexp.last_match(2) || 14).to_i # 目標値。省略時は14 if 空白 then 14 else 記載の値
  50. 2 fumble1 = (Regexp.last_match(4) || 21).to_i # 追加ファンブル値。省略時は21
  51. 2 fumble2 = (Regexp.last_match(6) || 21).to_i # 追加ファンブル値。省略時は21
  52. 2 critical = (Regexp.last_match(8) || 21).to_i # 追加クリティカル値。省略時は21
  53. when: 5 when /^(\d+)?CP(\d+)?(\[(\d+)(,(\d+))?\])?(@(\d+))?$/i
  54. 5 number = (Regexp.last_match(1) || 1).to_i
  55. 5 target = (Regexp.last_match(2) || 14).to_i
  56. 5 fumble1 = (Regexp.last_match(4) || 21).to_i
  57. 5 fumble2 = (Regexp.last_match(6) || 21).to_i
  58. 5 else: 5 critical = (Regexp.last_match(8) || 21).to_i
  59. 5 else return nil
  60. end
  61. 7 dice = 0
  62. 7 dicetext = ""
  63. 7 crit_flg = false
  64. 7 fumb_flg = false
  65. 7 succ_flg = false
  66. 7 number.times do
  67. 21 dice = @randomizer.roll_once(20)
  68. 21 then: 7 if dicetext == ""
  69. 7 dicetext = dice.to_s
  70. else: 14 else
  71. 14 dicetext = dicetext + "," + dice.to_s
  72. end
  73. 21 then: 2 if [1, critical].include?(dice)
  74. 2 else: 19 crit_flg = true
  75. 19 then: 4 elsif [20, fumble1, fumble2].include?(dice) # パラディーゾではクリティカル優先!
  76. 4 else: 15 fumb_flg = true
  77. 15 then: 10 else: 5 elsif dice <= target
  78. 10 succ_flg = true
  79. end
  80. end
  81. 7 then: 2 if crit_flg == true
  82. 2 else: 5 result = "クリティカル"
  83. 5 then: 2 elsif fumb_flg == true
  84. 2 else: 3 result = "ファンブル"
  85. 3 then: 2 elsif succ_flg == true
  86. 2 result = "成功"
  87. else: 1 else
  88. 1 result = "失敗"
  89. end
  90. 7 text = "(#{number}D20 目標値#{target}) > (#{dicetext}) > #{result}"
  91. 7 return text
  92. end
  93. # ダメージチェック DCa[20,30]
  94. 1 def getDamageResult(command)
  95. 5 biggun = [0, 0, 0]
  96. 5 case command
  97. when: 3 when /^DC(\d+)(\[(\d+)(,(\d+))?(,(\d+))?(,(\d+))?(,(\d+))?(,(\d+))?\])?$/i
  98. 3 attack = (Regexp.last_match(1) || 1).to_i # ダイス数。省略時は1
  99. 3 biggun[0] = (Regexp.last_match(3) || 0).to_i # コダワリ機銃、省略時は0
  100. 3 biggun[1] = (Regexp.last_match(5) || 0).to_i
  101. 3 biggun[2] = (Regexp.last_match(7) || 0).to_i
  102. 3 biggun[3] = (Regexp.last_match(9) || 0).to_i
  103. 3 biggun[4] = (Regexp.last_match(11) || 0).to_i
  104. 3 else: 2 biggun[5] = (Regexp.last_match(13) || 0).to_i
  105. 2 else return nil
  106. end
  107. 3 dice = 0
  108. 3 dicetext = ""
  109. 3 damage = Array.new(20, 0)
  110. 3 doubledam = 0
  111. 3 tripledam = 0
  112. 3 biggun.each do |bg|
  113. 18 else: 9 case bg
  114. when: 4 when 30
  115. 4 tripledam += 1
  116. when: 5 when 20
  117. 5 doubledam += 1
  118. end
  119. end
  120. 3 attack.times do
  121. 15 dice = @randomizer.roll_once(20)
  122. 15 then: 3 if dicetext == ""
  123. 3 dicetext = dice.to_s
  124. else: 12 else
  125. 12 dicetext = dicetext + "," + dice.to_s
  126. end
  127. 15 then: 4 if tripledam >= 1
  128. 4 damage[dice - 1] += 3
  129. 4 tripledam += -1
  130. 4 else: 11 dicetext += "【30mm】"
  131. 11 then: 5 elsif doubledam >= 1
  132. 5 damage[dice - 1] += 2
  133. 5 doubledam += -1
  134. 5 dicetext += "【20mm】"
  135. else: 6 else
  136. 6 damage[dice - 1] += 1
  137. end
  138. end
  139. 3 result = "\n#{damage[0]}#{damage[1]}#{damage[2]}#{damage[3]}#{damage[4]}\n#{damage[5]}#{damage[6]}#{damage[7]}#{damage[8]}#{damage[9]}\n#{damage[10]}#{damage[11]}#{damage[12]}#{damage[13]}#{damage[14]}\n#{damage[15]}#{damage[16]}#{damage[17]}#{damage[18]}#{damage[19]}"
  140. 3 text = "攻撃力#{attack}ダメージチェック > (#{dicetext}) > #{result}"
  141. 3 return text
  142. end
  143. # ラジオマリエッタ表
  144. 1 def get_radiomarietta_table
  145. 1 dice = @randomizer.roll_once(20)
  146. 1 else: 0 case dice
  147. when: 0 when 1
  148. text = "「なんてこった! ここで事故のお知らせだ!」\n通行止め……。ランダムなマス1つを決定する。この一日中、そのマスに移動する事はできない。"
  149. when: 1 when 2..4
  150. 1 text = "「今日はまたずいぶんと湿気てるねぇ……。古傷がある人は要注意だよ」\n天候が悪い。この一日中、「●移動」のアクションで移動できるマス数は常に1マス低くなる。"
  151. when: 0 when 5..10
  152. text = "「日常は至上! 異常は退場! なんにもないからラジオは以上! ……なんつて」\nいつもどおりの日々。のんびりとした風で、何事もなし。"
  153. when: 0 when 11, 12
  154. text = "「それじゃ、本日のメインコーナー。行ってみよう!」\n軽妙なトーク。PC全員の【乗り手コンディション】が1点小さくなる。"
  155. when: 0 when 13..15
  156. text = "「いーなー、こんな日はボクも飛んでみたい気分だよ! ブオノあたりまでバーッとね!」\nとんでもなく快晴で絶好のフライト日和。【機体コンディション】【乗り手コンディション】がそれぞれ1点小さくなる。"
  157. when: 0 when 16
  158. text = "「店頭で言えば嬉しい値引き。本日のラッキーワードをメモする用意はできたかい?」\nおトクな情報。この一日中、各PCごとに一回ずつ、「価格」の効果値が2低いものとして効果を処理できる(最低値0)"
  159. when: 0 when 17
  160. text = "「いっやー……熱演だったね。もーぅ次回が待ちきれなぁい!!」\nラジオドラマが神回だった。その日一日に行う「交流」で獲得できる【キズナ】の点数が+1される。"
  161. when: 0 when 18
  162. text = "「イエス!ナイス!エレガンス!あのサーカス団が帰ってくる!」\nサーカス団がやってくる!ランダムなマス1つを決定する。\nこの一日中、そのマスは「娯楽施設:5」(P.55)の効果を得る。"
  163. when: 0 when 19
  164. text = "「ラジオネーム、ハプニングさんからのお便り! おっとぉ、これは興味深い相談だ」\nラジオの話している内容から手がかりが見つかる。\[手がかり\]が1箇所追加で配置される。"
  165. when: 0 when 20
  166. text = "「今夜は素敵なパーリィデイ! みんな!今夜の仮装を何にするかはもう決めてるかな?」\n酒場でパーティだ!「酒場」のスポット効果を持つスポットに「レストラン:「パーティ」」が追加される。"
  167. end
  168. 1 return "ラジオマリエッタ表" + "\(" + dice.to_s + "\):" + text
  169. end
  170. # 移動表
  171. 1 def get_takeoff_table
  172. dice = @randomizer.roll_once(20)
  173. else: 0 case dice
  174. when: 0 when 1
  175. text = "エンジンがぶっ壊れた!ただちに【機体コンディション】が「20」となり、このターン中は2つ目のアクションも含め「●移動」することができない。"
  176. when: 0 when 2
  177. text = "離水に失敗した! キミの愛機のダメージマップ上の任意の「翼」部位のダメージボックスに1点のダメージを与え、このターン中は2つ目のアクションも含め「●移動」することができない。"
  178. when: 0 when 3
  179. text = "軽いエンジントラブル。このアクションでは移動することができない。"
  180. when: 0 when 4
  181. text = "同業者に遭遇。しかし煽られて曲芸飛行につきあわされる。\n任意の方向に強制的に3マス移動し、【物資点】3点を失う。"
  182. when: 0 when 5
  183. text = "道を間違えたらしい。【物資点】を5点消費し、ランダムな方向に1マス移動する効果を3回繰り返す。"
  184. when: 0 when 6
  185. text = "気づいたらオイル漏れを起こしていた!【物資点】を3点消費する。その後、1マスにつき1点の【物資点】を消費して最大4マスまで移動できる。"
  186. when: 0 when 7
  187. text = "あいにくのにわか雨。あまり飛びたくないなあ。1マスにつき1点の【物資点】を消費して最大2マスまで移動できる。"
  188. when: 0 when 8
  189. text = "唐突な襲撃。一撃加えたあと、謎の襲撃者はいずこかへ去っていった……。命中判定の達成値が12であると扱う、【火力】3のダメージチェックを受ける。その後、1マスにつき1点の【物資点】を消費して最大4マスまで移動できる。"
  190. when: 0 when 9
  191. text = "んー、少し調子が悪いかな? 1マスにつき1点の【物資点】を消費して最大3マスまで移動できる。"
  192. when: 0 when 10..12
  193. text = "順調な空の旅。1マスにつき1点の【物資点】を消費して最大5マスまで移動できる。"
  194. when: 0 when 13
  195. text = "島巡りの観光艇と遭遇。ちやほやされていい気分。1マスにつき1点の【物資点】を消費して最大5マスまで移動できる上、キミの【乗り手コンディション】を2点までの任意の点数下げる事ができる。"
  196. when: 0 when 14
  197. text = "同業者と遭遇。1マスにつき1点の【物資点】を消費して最大5マスまで移動できる上、同業者は「キミへの【キズナ】」を1点得る。同業者はこのセッション中、キミが望む場面でキミに「判定支援」を行ってくれる。"
  198. when: 0 when 15
  199. text = "すごく調子がいいぞ!1マスにつき1点の【物資点】を消費して最大7マスまで移動できる上、キミの【機体コンディション】を2点までの任意の点数下げる事ができる。"
  200. when: 0 when 16
  201. text = "すごく調子がいいぞ!1マスにつき1点の【物資点】を消費して最大5マスまで移動できる上、このアクションがこのターンに行う1回目のアクションである場合、2回目のアクションでも続けて「●移動」を行う事ができる。"
  202. when: 0 when 17
  203. text = "通りかかった先に思わぬ情報が!1マスにつき1点の【物資点】を消費して最大5マスまで移動できる上、このアクションがこのターンに行う1回目のアクションである場合、2回目のアクションでは今いるマスに\[手がかり\]が配置されているものとして「●探索」が行える。"
  204. when: 0 when 18
  205. text = "酒場が恋しい……。【物資点】を5点消費し、即座に同じ「クエストマップ」内の「酒場」のスポット効果を持つマスに移動する。"
  206. when: 0 when 19
  207. text = "アジトが恋しい……。【物資点】を5点消費し、即座に同じ「クエストマップ」内の任意のキミの「アジト」に移動する。"
  208. when: 0 when 20
  209. text = "仲間が恋しい……。【物資点】を5点消費し、即座に任意のPC一人のいる場所に移動する。"
  210. end
  211. return "移動表" + "\(" + dice.to_s + "\):" + text
  212. end
  213. # 探索表
  214. 1 def get_exploration_table
  215. dice = @randomizer.roll_once(20)
  216. else: 0 case dice
  217. when: 0 when 1
  218. text = "クソっ!このマスに付与されていた\[手がかり\]を失う。"
  219. when: 0 when 2
  220. text = "「ツケ払いやがれ!」見に覚えがあるかないか。キミに詰め寄ってくるヤツがいる。【物資点】を10点消費するか、「ツケを伸ばす」のどちらかを選択する。ツケを伸ばすを選択した場合、次にキミが行う「●探索」のアクションでも、探索表の結果は参照せず、自動的にこの効果が適用される。"
  221. when: 0 when 3
  222. text = "謎は深まる。このマスに付与されていた\[手がかり\]を失い、ランダムな場所に再付与する。【情報点】は得られない。"
  223. when: 0 when 4
  224. text = "コネクションは大事だ。「支援チェック」をチェックしていない【キズナ】が1点以上存在すれば、その「支援チェック」を入れたあと、このマスに付与されていた\[手がかり\]を失い、【情報点】を1点獲得する。"
  225. when: 0 when 5..8
  226. text = "情報を手に入れるためには、少し骨を折る必要がありそうだ。好きな能力値を2つ組み合わせて{探索判定}を行う。成功すればこのマスに付与されていた\[手がかり\]を失い、【情報点】を1点獲得する。"
  227. when: 0 when 9
  228. text = "情報を提供してくれるというアイツは見返りを要求してきた。【物資点】を4点消費できる。そうした場合、このマスに付与されていた\[手がかり\]を失い、【情報点】を1点獲得する。"
  229. when: 0 when 10..13
  230. text = "危なげなく情報ゲット。このマスに付与されていた\[手がかり\]を失い、【情報点】を1点獲得する。"
  231. when: 0 when 14
  232. text = "手がかりを追っている事を話すと、ソイツは協力を持ちかけてきてくれた。このマスに付与されていた\[手がかり\]を失い、【情報点】を1点獲得する。さらに、【物資点】を5点獲得する。"
  233. when: 0 when 15
  234. text = "手がかりを追っている事を話すと、ソイツは協力を持ちかけてきてくれた。このマスに付与されていた\[手がかり\]を失い、【情報点】を1点獲得する。さらに、アイテム「チケット」(P\.69)を入手する。"
  235. when: 0 when 16
  236. text = "昔の仲間から手がかりについて聞くことになった。ついでに積もる話も少々。このマスに付与されていた\[手がかり\]を失い、【情報点】を1点獲得する。さらに同業者は「キミへの【キズナ】」を1点得る。同業者はこのセッション中、キミが望む場面でキミに「判定支援」を行ってくれる。"
  237. when: 0 when 17
  238. text = "空軍にいる友人から手がかりについて聞くことになった。「なあ、お前もフラフラしてないで空軍に入ったらどうだ?」耳に痛い。このマスに付与されていた\[手がかり\]を失い、【情報点】を1点獲得する。さらに、アイテム「空軍のツテ」(P\.69)を入手する。"
  239. when: 0 when 18
  240. text = "手がかりを追っていたら他にもボロボロと……。このマスに付与されていた\[手がかり\]を失い、【情報点】を1点獲得する。さらに、1D20を二回振り、この「クエストマップ」上のランダムなマス2つを求める。それらのマスに\[手がかり\]が付与されていなければ、\[手がかり\]を付与する。"
  241. when: 0 when 19
  242. text = "あっさり情報を掴むことができてしまった。このマスに付与されていた\[手がかり\]を失い、【情報点】を1点獲得する。この「●探索」ではアクションを消費せず、追加で別のアクションを宣言する事ができる。"
  243. when: 0 when 20
  244. text = "これは重要な手がかりだ! このマスに付与されていた\[手がかり\]を失い、【情報点】を2点獲得する。"
  245. end
  246. return "探索表" + "\(" + dice.to_s + "\):" + text
  247. end
  248. # 補給表
  249. 1 def get_flightsupply_table
  250. 1 dice = @randomizer.roll_once(20)
  251. 1 else: 0 case dice
  252. when: 0 when 1
  253. text = "……えっ?! キミの【物資点】は0点となる。"
  254. when: 0 when 2
  255. text = "おいおい勘弁してくれよ……。このアクションがそのセグメントの一回目のアクションだった場合、キミは2回目のアクションを行えない。その後【物資点】を5点獲得する。"
  256. when: 0 when 3
  257. text = "取材に巻き込まれる。【物資点】は獲得できないが、記者の発言からはぽろりとなにかが見えたような?1D20を振り、出た目に対応したマスに「手がかり」を1つ配置する。"
  258. when: 0 when 4
  259. text = "成果ゼロ。ま、こんな日もあるかな。【物資点】は獲得できない。"
  260. when: 0 when 5
  261. text = "うまいこと補給できなかった。【物資点】を5点獲得する。"
  262. when: 1 when 6
  263. 1 text = "「一稼ぎと言ったらこれだろ?」と声をかけてくる悪友たち。「カジノ」(『基本ルールブック』P\.55)のスポット効果を即座に適用する。ただしこの処理では判定の失敗により「刑務所」のスポット効果を持つスポットに移動する効果は発生せず、代わりに「酒場」のスポット効果を持つスポットに移動した上で、自身が持つ全ての【キズナ】の「支援チェック」にチェックを入れる。その後、次のセグメントが終了するまでの間アクションは行えない。"
  264. when: 0 when 7..9
  265. text = "のんびり釣りといこう。釣果は運次第だ。1D20を振り、出た目と同じ数だけ【物資点】を獲得する。"
  266. when: 0 when 10..12
  267. text = "なにごともなく補給が完了する。【物資点】を10点獲得する。"
  268. when: 0 when 13
  269. text = "ラジオの音が聞こえる。PCが望むなら、1D20を振り、出た目を「ラジオ・マリエッタ表」(『基本ルールブック』P.29)に照らし合わせて、その結果を反映する。これ以後、朝セグメントで振られたラジオ・マリエッタ表の効果は失われる。その後【物資点】を10点獲得する。"
  270. when: 0 when 14
  271. text = "補給の合間、ちょっと口寂しくなってしまって露店へ。【物資点】を8点獲得し、アイテム「レモネード」(『基本ルールブック』P\.69)を入手する。"
  272. when: 0 when 15
  273. text = "補給の合間、軽くメンテナンス。【機体コンディション】を1点下げることができる。その後【物資点】を10点獲得する。"
  274. when: 0 when 16
  275. text = "補給の合間、店主と軽く談笑。【乗り手コンデイション】を1点下げることができる。その後【物資点】を10点獲得する。"
  276. when: 0 when 17
  277. text = "補給の合間、仲間に軽く挨拶しておこうか。同じマスに他のPCがいた場合、そのPC1人への【キズナ】を1点獲得する。その後【物資点】を10点獲得する。"
  278. when: 0 when 18
  279. text = "補給の合間に通りがかった相手と意気投合。相手はキミへの【キズナ】を1点取得する。【物資点】を10点獲得する。"
  280. when: 0 when 19
  281. text = "あっさり補給が終わってしまった。どうしようかな。この補給ではアクションを消費せず、【物資点】を10点獲得する。"
  282. when: 0 when 20
  283. text = "降って湧いた幸運!【物資点】が20点になる。"
  284. end
  285. 1 return "補給表" + "\(" + dice.to_s + "\):" + text
  286. end
  287. end
  288. end
  289. end

lib/bcdice/game_system/Paranoia.rb

100.0% lines covered

57.14% branches covered

28 relevant lines. 28 lines covered and 0 lines missed.
7 total branches, 4 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Paranoia < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Paranoia'
  7. # ゲームシステム名
  8. 1 NAME = 'パラノイア'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'はらのいあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ※「パラノイア」は完璧なゲームであるため特殊なダイスコマンドを必要としません。
  14. ※このダイスボットは部屋のシステム名表示用となります。
  15. MESSAGETEXT
  16. 1 register_prefix('geta')
  17. 1 def initialize(command)
  18. 9 super(command)
  19. 9 @enabled_upcase_input = false
  20. end
  21. 1 def eval_game_system_specific_command(command)
  22. 2 debug('eval_game_system_specific_command command', command)
  23. 2 result = ''
  24. 2 else: 0 case command
  25. when: 2 when /geta/i
  26. 2 result = getaRoll()
  27. end
  28. 2 then: 0 else: 2 return nil if result.empty?
  29. 2 return "#{command} > #{result}"
  30. end
  31. 1 def getaRoll()
  32. 2 result = ""
  33. 2 dice = @randomizer.roll_once(2)
  34. 2 result += "幸福ですか? > "
  35. 2 getaString = ''
  36. 2 else: 0 case dice
  37. when: 1 when 1
  38. 1 getaString = '幸福です'
  39. when: 1 when 2
  40. 1 getaString = '幸福ではありません'
  41. end
  42. 2 result += getaString
  43. 2 return result
  44. end
  45. end
  46. end
  47. end

lib/bcdice/game_system/ParanoiaRebooted.rb

94.12% lines covered

76.92% branches covered

51 relevant lines. 48 lines covered and 3 lines missed.
13 total branches, 10 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class ParanoiaRebooted < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'ParanoiaRebooted'
  7. # ゲームシステム名
  8. 1 NAME = 'パラノイア リブーテッド'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'はらのいありふうてつと'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ※コマンドは入力内容の前方一致で検出しています。
  14. ・通常の判定 NDx
  15.  x:ノードダイスの数.マイナスも可.
  16.  ノードダイスの絶対値 + 1個(コンピュータダイス)のダイスがロールされる.
  17. 例)ND2 ND-3
  18. ・ミュータントパワー判定 MPx
  19. x:ノードダイスの数.
  20.  ノードダイスの値 + 1個(コンピュータダイス)のダイスがロールされる.
  21. 例)MP2
  22. INFO_MESSAGE_TEXT
  23. 1 register_prefix('ND', 'MP')
  24. 1 def eval_game_system_specific_command(command)
  25. 13 case command
  26. when: 9 when /^ND/i
  27. 9 return get_node_dice_roll(command)
  28. when: 4 when /^MP/i
  29. 4 return get_mutant_power_roll(command)
  30. else: 0 else
  31. return nil
  32. end
  33. end
  34. 1 private
  35. 1 def generate_roll_results(dices)
  36. 13 computer_dice_message = ''
  37. 13 results = dices.dup
  38. 13 then: 6 else: 7 if results[-1].to_i == 6
  39. 6 results[-1] = 'C'
  40. 6 computer_dice_message = '(Computer)'
  41. end
  42. 13 return results, computer_dice_message
  43. end
  44. 1 def get_node_dice_roll(command)
  45. 9 debug("eval_game_system_specific_command Begin")
  46. 9 m = /^ND((-)?\d+)/i.match(command)
  47. 9 else: 9 then: 0 unless m
  48. return ''
  49. end
  50. 9 debug("command", command)
  51. 9 parameter_num = m[1].to_i
  52. 9 dice_count = parameter_num.abs + 1
  53. 9 dices = @randomizer.roll_barabara(dice_count, 6)
  54. 34 success_rate = dices.count { |dice| dice >= 5 }
  55. 20 then: 3 else: 6 success_rate -= dices.count { |dice| dice < 5 } if parameter_num < 0
  56. 9 debug(dices)
  57. 9 results, computer_dice_message = generate_roll_results(dices)
  58. 9 debug("eval_game_system_specific_command result")
  59. 9 return "(#{command}) > [#{results.join(', ')}] > 成功度#{success_rate}#{computer_dice_message}"
  60. end
  61. 1 def get_mutant_power_roll(command)
  62. 4 debug("eval_game_system_specific_command Begin")
  63. 4 m = /^MP(\d+)/i.match(command)
  64. 4 else: 4 then: 0 unless m
  65. return ''
  66. end
  67. 4 debug("command", command)
  68. 4 parameter_num = m[1].to_i
  69. 4 dice_count = parameter_num.abs + 1
  70. 4 dices = @randomizer.roll_barabara(dice_count, 6)
  71. 4 failure_rate = dices.count(1)
  72. 4 then: 2 else: 2 message = failure_rate == 0 ? '成功' : "失敗(#{failure_rate})"
  73. 4 results, computer_dice_message = generate_roll_results(dices)
  74. 4 debug(dices)
  75. 4 debug("eval_game_system_specific_command result")
  76. 4 return "(#{command}) > [#{results.join(', ')}] > #{message}#{computer_dice_message}"
  77. end
  78. end
  79. end
  80. end

lib/bcdice/game_system/ParasiteBlood.rb

88.37% lines covered

70.59% branches covered

43 relevant lines. 38 lines covered and 5 lines missed.
17 total branches, 12 branches covered and 5 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/DemonParasite'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class ParasiteBlood < DemonParasite
  6. # ゲームシステムの識別子
  7. 1 ID = 'ParasiteBlood'
  8. # ゲームシステム名
  9. 1 NAME = 'パラサイトブラッドRPG'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'はらさいとふらつとRPG'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・衝動表 (URGEx)
  15.  "URGE衝動レベル"の形で指定します。
  16.  衝動表に従って自動でダイスロールを行い、結果を表示します。
  17.  ダイスロールと同様に、他のプレイヤーに隠れてロールすることも可能です。
  18.  頭に識別文字を追加して、デフォルト以外の衝動表もロールできます。
  19.  ・AURGEx 頭に「A」を付けると「誤作動表」。
  20. 例)URGE1   urge5   Aurge2
  21. ・D66ダイスあり
  22. INFO_MESSAGE_TEXT
  23. 1 register_prefix('[NAMUC]?URGE')
  24. 1 def get_urge(string) # パラサイトブラッドの衝動表
  25. 100 else: 100 then: 0 unless /(\w*)URGE\s*(\d+)/i =~ string
  26. return '1'
  27. end
  28. 100 initialWord = Regexp.last_match(1)
  29. 100 urgelv = Regexp.last_match(2).to_i
  30. 100 case initialWord
  31. when: 40 when ""
  32. 40 urge_type = 1
  33. when: 50 when /A/i # 誤作動表
  34. 50 urge_type = 2
  35. else: 10 else # あり得ない文字
  36. 10 urge_type = 1
  37. end
  38. 100 then: 0 else: 100 if (urgelv < 1) || (urgelv > 5)
  39. return '衝動段階は1から5です'
  40. end
  41. 100 then: 0 else: 100 if urge_type == 0
  42. return '1'
  43. end
  44. 100 dice_now = @randomizer.roll_sum(2, 6)
  45. 100 urge = get_pb_urge_table(urgelv, dice_now, urge_type)
  46. 100 resultText = "#{urgelv}-#{dice_now}:#{urge}"
  47. 100 then: 50 if urge_type <= 1
  48. 50 else: 50 output = "衝動表#{resultText}"
  49. 50 then: 50 elsif urge_type <= 2
  50. 50 output = "誤作動表#{resultText}"
  51. else: 0 else
  52. output = '1'
  53. end
  54. 100 return output
  55. end
  56. 1 def get_pb_urge_table(level, dice, urge_type)
  57. 100 table = nil
  58. 100 then: 50 if urge_type <= 1 # 衝動表
  59. 50 else: 50 table = get_pb_normal_urge_table
  60. 50 then: 50 elsif urge_type <= 2 # AASとサイボーグの誤作動表
  61. 50 table = get_pb_aas_urge_table
  62. else: 0 else # エラートラップ
  63. table = get_pb_normal_urge_table
  64. end
  65. 100 return table[level - 1][dice - 2]
  66. end
  67. 1 def get_pb_normal_urge_table
  68. 50 return [[
  69. '『怒り/20』突然強い怒りに駆られる。最も近い対象を罵倒し、そのターンの終了まで[行動不能]となる。',
  70. '『暗闇/20』視神経に悪影響が出て、24時間[暗闇]になる。',
  71. '『悲哀/10』突然の悲みに動きが止まる。そのターンの終了まで[行動不能]となる。',
  72. '『微笑/10』可笑しくてしょうがない。笑いが止まらず、そのターンの終了まで[行動不能]となる。',
  73. '『鈍感/ 0』衝動に気が付かない。影響なし。',
  74. '『抑制/ 0』衝動を抑制した。影響なし。',
  75. '『我慢/ 0』衝動を我慢した。影響なし。',
  76. '『前兆/10』悪魔的特徴が1ターン(10秒)目立つ。〈悪魔化〉時は影響なし。',
  77. '『変化/10』利き腕や前脚のみ、2ターン(20秒)かけて〈悪魔化〉する。〈悪魔化〉時は影響なし。',
  78. '『拒絶/10』〈悪魔化〉が解除される。通常時は影響なし。',
  79. '『定着/20』通常時であれば、即座に〈悪魔化〉する。肉体が〈悪魔化〉に馴染み、24時間通常時に戻れない。',
  80. ],
  81. [
  82. '『賛美/20』最も近くの対象を主と思いこむ。1時間または自身か対象が[気絶・戦闘不能・死亡]するまで、対象のあらゆる命令を聞く。',
  83. '『茫然/20』思考が停止。そのターンの終了まで[タイミング:攻撃]を行えない。',
  84. '『苦痛/20』"悪魔寄生体"が体内で暴れる。苦痛を感じ、【エナジー】を10消費。',
  85. '『落涙/10』過去の悲しい想い出が去来し、涙が溢れる。そのターンの終了まで[タイミング:準備]を行えない。',
  86. '『限界/10』溢れる力が限界を超え、全身の血管が破裂。【エナジー】を5消費。',
  87. '『辛抱/10』突如全身が〈悪魔化〉しようとしたが、意思の力で抑制。【エナジー】を5消費。〈悪魔化〉時は影響なし。',
  88. '『忍耐/ 0』衝動に耐えた。影響なし。',
  89. '『抑制/ 0』衝動を抑制した。影響なし。',
  90. '『我慢/ 0』衝動を我慢した。影響なし。',
  91. '『嫉妬/10』最も近くの対象に猛烈な嫉妬を感じ、[距離:移動10m/対象:1体]に通常肉弾攻撃を行う。',
  92. '『変貌/20』〈悪魔化〉する。その際、特異な外見が目立つ。〈悪魔化〉時は影響なし。',
  93. ],
  94. [
  95. '『異貌/20』3ターンかけて、顔のみが〈悪魔化〉する。〈悪魔化〉時は影響なし。',
  96. '『解放/20』衝動に耐えきれず3ターンかけて〈悪魔化〉する。〈悪魔化〉時は影響なし。',
  97. '『発露/20』全身を駆け抜ける衝動により力が溢れる。次のターンの終了まで、ダメージに+5。',
  98. '『渇望/10』攻撃衝動を抑えられない。次のターンの終了まで、命中判定の達成値に+5。',
  99. '『絶叫/10』あらん限りの声で叫び、力が増す。次のターンの終了まで、ダメージに+1d。',
  100. '『我慢/ 0』衝動を我慢した。影響なし。',
  101. '『憤怒/10』全身に怒りが満ちて攻撃力上昇。次のターンの終了まで、ダメージに+1d。',
  102. '『加速/10』全身を駆け抜ける衝動により速度上昇。次のターンの終了まで【行動値】が2倍。',
  103. '『嫌悪/20』最も近くの対象に嫌悪を感じ、[距離:移動10m/対象:1体]に通常肉弾攻撃を行う。',
  104. '『保身/20』突如として防御能力が高まる。次のターンの終了まで、防御力に+5。',
  105. '『救済/20』"悪魔寄生体"が危機を察知し、【エナジー】を20回復。',
  106. ],
  107. [
  108. '『転倒/20』踏み込んだ瞬間、あまりの衝撃に地面をえぐり[転倒]してしまう。',
  109. '『脱力/20』急に力が抜ける。そのターンの終了まで、判定の達成値に-5。',
  110. '『困惑/20』精神に変調があらわれ、空間認識能力が狂う。次のターンの終了まで、[タイミング:瞬間]の《特殊能力》を行えない。',
  111. '『全力/20』激しい躁状態。次のターンの終了まで、命中判定に+10。加えて[タイミング:ターン開始]の《特殊能力》を使用できなくなる。',
  112. '『咆吼/10』大声で叫び、意味のある言葉を話せなくなる。1時間持続する。',
  113. '『狂気/10』心が狂気に満たされ、強いストレスを感じる。【衝動】を2蓄積させる。',
  114. '『本能/20』"悪魔寄生体"の生存本能が自我を支配。次のターンの終了まで、ダメージに+5。',
  115. '『治癒/20』衝動を1蓄積させ、《肉体修復》を行う。',
  116. '『敵意/20』最も近い対象に強い敵意を抱く。[距離:移動10m/対象:1体]に通常肉弾攻撃を行い、クリティカルとなる。',
  117. '『自虐/20』自分が許せず自虐行為を行う。【エナジー】を10消費するが、次のターンの終了までダメージに+10。',
  118. '『自浄/20』少し我に返る。【衝動】が2回復。',
  119. ],
  120. [
  121. '『睡眠/30』猛烈な睡魔に襲われ意識を失う。そのターンの終了まで[気絶]となる。',
  122. '『飢餓/30』猛烈な飢餓感。20m以内の最も近い[気絶・戦闘不能・死亡]の対象へ移動し、喰らう。次のターンの終了まで、対象は【エナジー】を1dずつ消費。',
  123. '『激怒/20』突如として強い怒りが湧き、周囲が見えなくなる。次のターンの終了まで、[タイミング:瞬間]の《特殊能力》を行えない。',
  124. '『顕現/20』利き腕や前脚がさらに外骨格化し、肉体に強い負荷がかかる。【衝動】を3蓄積',
  125. '『好機/20』チャンスに本能が素早く反応。即座に[タイミング:攻撃]の行動を1回だけ行える。',
  126. '『狂化/20』精神に変調、心が強い狂気で満たされ、自虐行為に走る。【エナジー】を20消費する。',
  127. '『混乱/20』精神に変調が現れ、肉体を意のままに動かせない。次のターンの終了まで、判定の達成値に-5。',
  128. '『暴君/20』自分が最強に思えてしょうがない。60ターン(10分)の間、【行動値】とダメージに+5。',
  129. '『無双/20』達人の感覚が目覚める。60ターン(10分)の間、命中判定と回避判定の達成値に+5。',
  130. '『発現/30』通常時であれば、即座に《悪魔化》する。特異な外見が60ターン(10分)目立ち、その間、命中判定とダメージに+5。',
  131. '『絶望/30』全身が絶望に満たされ、全てを破壊したくなる。次のターンの終了まで、ダメージに+15。',
  132. ]]
  133. end
  134. # **パラサイトブラッドの誤作動表(2d6)
  135. 1 def get_pb_aas_urge_table
  136. 50 return [[
  137. # **第1段階
  138. '『緊急停止/20』機能異常の警報と共に、機能が緊急停止。次のターンのターン終了時まで[行動不能]となる。',
  139. '『動作不調/10』駆動系に異常発生。このターンのターン終了まで[行動不能]となる。',
  140. '『腕部停止/10』腕部機能に異常発生。このターンのターン終了まで[タイミング:攻撃]を失う。',
  141. '『視覚異常/10』センサー系に異常。60ターン(10分)の間、[暗闇]となる。',
  142. '『機能制動/0』機能が一瞬停止するが、以後正常に動作。影響なし。',
  143. '『機能安定/0』機能がむしろ安定した。影響なし。',
  144. '『不良調整/0』機能に違和感を覚えるが誤差の範囲内。影響なし。',
  145. '『機能暴発/10』兵装の調子が悪化。次のターンのターン終了まで、[タイミング:準備]の《兵装》が使用できない。',
  146. '『離脱機能/10』異常発生。即座に[戦闘移動]を行い、最も近い敵から遠ざかるように移動する。',
  147. '『排熱暴走/10』排熱機能に異常。次のターンのターン終了まで[着火]状態となる。特殊ダメージは本人のものを使用する。',
  148. '『電装異常/20』電装系に異常。即座に【負荷】が2点蓄積する。',
  149. ],
  150. # **第2段階
  151. [
  152. '『安全機能/20』セーフティが誤動作。このターンのターン終了まで判定の達成値に-5。',
  153. '『筋肉萎縮/20』人工筋肉に異常発生。60ターン(10分)の間、【肉体】判定の達成値に-2。',
  154. '『出力低下/20』駆動部に異常発生。60ターン(10分)の間、【機敏】判定の達成値に-2。',
  155. '『感覚異常/10』感覚機能に異常発生。60ターン(10分)の間、【感覚】判定の達成値に-2。',
  156. '『視界不良/10』視覚機能に異常発生。60ターン(10分)の間、【幸運】判定の達成値に-2。',
  157. '『機能安定/0』機能がむしろ安定した。影響なし。',
  158. '『不良調整/0』機能に違和感を覚えるが誤差の範囲内。影響なし。',
  159. '『援護不通/10』援護ソフトが誤作動。60ターン(10分)の間、【知力】判定の達成値に-2。',
  160. '『発声不調/20』通話機能に異常。60ターン(10分)の間、声を出しても雑音だらけになって意味が通じず、さらに【精神】判定の達成値に-2。',
  161. '『装甲軟化/20』防御機能に異常。次のターンのターン終了まで、防御力に-5。',
  162. '『装備異常/20』精密動作に異常発生。装備している[通常アイテム]の武器がランダムでひとつ、[装備]から外れる。',
  163. ],
  164. # **第3段階
  165. [
  166. '『動力漏電/20』動力が漏電し始める。【負荷】が2点蓄積する。',
  167. '『脚部異常/20』脚部に異常発生。次のターンのターン終了まで[戦闘移動][全力移動]の距離が半分になる。',
  168. '『足下転倒/20』バランサーに異常発生。[転倒]状態となる。',
  169. '『出力向上/20』突然出力が上昇する。次のターンのターン終了まで、特殊ダメージに+1d。',
  170. '『機能制動/10』一瞬違和感を覚えるが、以後正常に動作。影響なし。',
  171. '『障壁減衰/10』電力が減衰する。【電力】を5消費する。',
  172. '『身体向上/10』格闘機能が向上。次のターンのターン終了まで、肉弾ダメージに+1d。',
  173. '『精度向上/20』火器管制機能が向上。次のターンのターン終了まで、射撃ダメージに+1d。',
  174. '『反射鋭化/20』反応速度が加速した。次のターンのターン終了まで、【行動値】に+5。',
  175. '『友軍誤認/20』警戒装置が誤動。最も近い[距離:移動10m/対象:1体]に通常肉弾攻撃を行う。',
  176. '『電子賦活/20』電磁障壁が突如復帰。【電力】が10回復する。',
  177. ],
  178. # **第4段階
  179. [
  180. '『照準誤認/20』照準機能に異常発生。最も近い[距離:移動10m/対象:1体]に通常肉弾攻撃を行う。判定は自動的にクリティカルとなる。',
  181. '『攻撃特化/20』攻撃機能が異常動作。次のターンのターン終了まで、ダメージに+2d。ただし、その間[タイミング:瞬間]を行えない。',
  182. '『機内窒息/20』呼吸機能に異常。次のターンのターン終了まで[窒息]状態となる。',
  183. '『自動援護/20』援護機能が自動的に作動する。即座に[タイミング:準備]を1回行う。',
  184. '『音声遮断/10』聴覚機能に異常発生。次のターンのターン終了まで一切の物音が聞こえず、回避判定の達成値に-5。',
  185. '『電流加速/10』突然電磁障壁が効率的に流れる。【電力】が10回復。',
  186. '『精密射撃/20』照準機能が向上。60ターン(10分間)の間、ダメージに+5。',
  187. '『緊急措置/20』突然、緊急時の対策機能が発動する。【負荷】が2蓄積し、【電力】が20回復する。',
  188. '『荷電暴走/20』電流の流れに異常が発生。【HP】を10消費し、次のターンのターン終了までダメージに+10。',
  189. '『状況分析/20』周辺解析ソフトが高速で動作。60ターン(10分間)の間、命中判定の達成値に+5。',
  190. '『機能再生/20』兵装に誤作動。取得済みの使用不能になった《兵装》を1つ指定し、再び使用できるようになる。',
  191. ],
  192. # **第5段階
  193. [
  194. '『機能停止/30』機能が作動しなくなる。このターンのターン終了まで、【負荷】を蓄積させる行動が取れなくなる。',
  195. '『機関暴走/30』放熱機関が暴走する。本人を中心として[対象:半径5m全て]が次のターンのターン終了まで[着火]状態となる。特殊ダメージはこの表を振ったPCのものを使用する。',
  196. '『電力低下/20』出力が上がらない。【電力】が20減少する。',
  197. '『急速修復/20』電磁障壁と生命維持装置が高速処理を始める。【HP】が20回復。',
  198. '『駆動不調/20』駆動系に動作不良。次のターンのターン終了まで、判定の達成値に-5。',
  199. '『機体清冽/20』機能が初期化され、異常から復帰。[気絶・死亡・戦闘不能]以外の状態変化がすべて解除される。',
  200. '『機体減速/20』運動機能が暴走。次のターンのターン終了まで【行動値】に-10(最低1)。',
  201. '『排毒噴出/20』排気機構が誤作動。[対象:半径5m全て]が次のターンのターン終了まで[猛毒]状態となる。',
  202. '『緊急駆動/20』機動性が向上。次のターンのターン終了まで判定の達成値に+5。',
  203. '『負荷軽減/30』急激に負荷が解消される。【負荷】が2点回復する。',
  204. '『出力過剰/30』全出力が過剰なまでに上昇する。次のターンのターン終了までダメージに+10。',
  205. ]]
  206. end
  207. end
  208. end
  209. end

lib/bcdice/game_system/PastFutureParadox.rb

100.0% lines covered

96.88% branches covered

110 relevant lines. 110 lines covered and 0 lines missed.
32 total branches, 31 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class PastFutureParadox < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "PastFutureParadox"
  7. # ゲームシステム名
  8. 1 NAME = "パストフューチャーパラドックス"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "はすとふゆうちやあはらとつくす"
  11. 1 HELP_MESSAGE = <<~TEXT
  12. ・行為判定 PP@s#f[+m/-m]>=x  2D6の行為判定を行う。
  13.  s: スペシャル値 (省略時 12)、 f: ファンブル値 (省略時 2)
  14.  [+m/-m]: 修正値(省略可)、 x: 目標値 (省略可)
  15.  例)PP, PP-1, PP@11, PP@11+2, PP@11#3, PP@11#3-1,
  16.    PP#3>=7, PP#3+2>=7, PP>=7, PP-1>=7
  17. ・特技表
  18. ランダム分野表 RCT
  19. ランダム特技表 RTTn(n:分野番号、省略時は全分野からランダム)
  20.  科学 (RTT1)、知識(RTT2)、身体(RTT3)、
  21.  センス(RTT4)、知恵(RTT5)、迷信(RTT6)
  22. ・各種表 ※1D6および2D6を振る表は、末尾に=nと付けることで出目nの内容を指定可能。末尾に-n/+nと付けることで、出目に修正を付けることが可能。
  23.  例:SBET=2 MBET-1 TBET+2
  24. シーン表(2D6)
  25.  現代シーン表 ST4
  26. 経歴表(D66)
  27.  原始時代経歴表 CT1 、古代経歴表 CT2 、中世時代経歴表 CT3
  28.  現代経歴表 CT4 、超情報化時代経歴表 CT5 、宇宙時代経歴表 CT6
  29. 名前表(D66)
  30.  原始時代名前表(男性名) NMT1 、原始時代名前表(女性名) NFT1
  31.  古代名前表(男性名) NMT2 、古代名前表(女性名) NFT2 、古代名前表(姓) NLT2
  32.  中世時代(日本)名前表(男性名) NMT3 、中世時代(日本)名前表(女性名) NFT3 、中世時代(日本)名前表(姓) NLT3
  33.  中世時代(西洋)名前表(男性名) NMT3W 、中世時代(西洋)名前表(女性名) NFT3W 、中世時代(西洋)名前表(姓) NLT3W
  34.  現代(日本)名前表(男性名) NMT4 、現代(日本)名前表(女性名) NFT4 、現代(日本)名前表(姓) NLT4
  35.  現代(西洋)名前表(男性名) NMT4W 、現代(西洋)名前表(女性名) NFT4W 、現代(西洋)名前表(姓) NLT4W
  36.  超情報化時代名前表(男性名) NMT5 、超情報化時代名前表(女性名) NFT5 、超情報化時代名前表(姓) NLT5
  37.  宇宙時代名前表(男性名) NMT6 、宇宙時代名前表(女性名) NFT6 、宇宙時代名前表(姓) NLT6
  38. 因縁種別表(D66) CTT 、ポジティブ因縁内容表(1D6) CPT 、ネガティブ因縁内容表(1D6) CNT
  39. バタフライエフェクト表(2D6) ※バタフライエフェクト表は-5~12までの結果を算出可能
  40.  重度バタフライエフェクト表 SBET 、軽度バタフライエフェクト表 MBET 、タイムトラベラー重度バタフライエフェクト表 TBET
  41. アクシデント表(2D6) ACT 、タイムトラベル演出表(2D6) TT 、帰還演出表(1D6) RT
  42. アイテム決定表(1D6) IT 、時代決定表(1D6) AGT
  43. ・D66ダイスあり
  44. TEXT
  45. 1 def initialize(command)
  46. 158 super(command)
  47. 158 @sort_add_dice = false
  48. 158 @sort_barabara_dice = false
  49. 158 @d66_sort_type = D66SortType::ASC
  50. end
  51. 1 register_prefix('PP')
  52. 1 def eval_game_system_specific_command(command)
  53. 149 return action_roll(command) || RTT.roll_command(@randomizer, command) || roll_tables(command, TABLES) || roll_table_command(command)
  54. end
  55. 1 RTT = DiceTable::SaiFicSkillTable.new(
  56. [
  57. ['科学', ['人工知能', '計算機', '電子工学', '機械工学', '物理学', '数学', '天文学', '地学', '化学', '医療', 'バイオ技術']],
  58. ['知識', ['帝王学', '経済', '政治', '社会', '法律', '情報', '労働', '教育', '歴史', '語学', '文学']],
  59. ['身体', ['狙う', '斬る', '殴る', '跳ぶ', '走る', '避ける', '柔軟', '持ち上げる', '食べる', '飲む', '叫ぶ']],
  60. ['センス', ['魔法', '超能力', '第六感', '宗教', '倫理', '観察', '我慢', '操縦', '哲学', '心理', '芸術']],
  61. ['知恵', ['戦略', '方便', '機転', '洞察力', '記憶力', '段取り', '応急処置', '漢方', '胆力', '勘', '人徳']],
  62. ['迷信', ['思い込み', 'インチキ', '未確認物体', '雨乞い', '風水', '占い', '縁起', '魔除け', '心霊', '運命', '民間伝承']],
  63. ],
  64. s_format: "分野「%<category_name>s」《%<skill_name>s》",
  65. rtt_format: "ランダム指定特技表(%<category_dice>d,%<row_dice>d) > %<text>s"
  66. )
  67. 1 private
  68. 1 def roll_table_command(command)
  69. 98 result = []
  70. 98 m = /([A-Za-z0-9]+)(([+]|-|=)((-\d+)|\d+))?/.match(command)
  71. 98 else: 98 then: 0 return result unless m
  72. 98 command = m[1]
  73. 98 operator = m[3]
  74. 98 value = m[4].to_i
  75. 98 result = get_table_result(command, operator, value)
  76. 98 return result.join("\n")
  77. end
  78. 1 def get_table_result(command, operator, value)
  79. 98 result = []
  80. 98 then: 30 if !(table = TABLES_MOD_2D[command]).nil?
  81. 30 else: 68 result = get_table_index(table, operator, value, 2, 6)
  82. 68 then: 35 elsif !(table = TABLES_MOD_1D[command]).nil?
  83. 35 else: 33 result = get_table_index(table, operator, value, 1, 6)
  84. 33 then: 27 else: 6 elsif !(table = TABLES_MOD_MINUS[command]).nil?
  85. 27 result = get_table_minus_index(table, operator, value)
  86. end
  87. 98 return result
  88. end
  89. 1 def get_table_minus_index(table, operator, value)
  90. 27 index = 7
  91. 27 modify = 0
  92. 27 dice_list = nil
  93. 27 result = []
  94. 27 if operator == "="
  95. then: 9
  96. 9 index = value + 7
  97. 9 index = index.clamp(2, 19)
  98. 9 info = get_table_info(table, index)
  99. 9 text = "#{info.table_name}:#{info.value - 7} > #{info.value - 7}:#{info.body}"
  100. else
  101. else: 18
  102. 18 else: 3 case operator
  103. when: 6 when "+"
  104. 6 modify = value
  105. when: 9 when "-"
  106. 9 modify = value * -1
  107. end
  108. 18 dice_list = @randomizer.roll_barabara(2, 6)
  109. 18 index += dice_list.sum
  110. 18 index += modify
  111. 18 index = index.clamp(2, 19)
  112. 18 info = get_table_info(table, index)
  113. 18 then: 15 if modify != 0
  114. 15 text = "#{info.table_name}:#{dice_list.sum}[#{dice_list.join(',')}]#{operator}#{modify.abs} > #{info.value - 7}:#{info.body}"
  115. else: 3 else
  116. 3 text = "#{info.table_name}:#{dice_list.sum}[#{dice_list.join(',')}] > #{info.value - 7}:#{info.body}"
  117. end
  118. end
  119. 27 result.push(text)
  120. 27 return result
  121. end
  122. 1 def get_table_index(table, operator, value, dice_count, dice_type)
  123. 65 index = 0
  124. 65 modify = 0
  125. 65 dice_list = nil
  126. 65 result = []
  127. 65 if operator == "="
  128. then: 22
  129. 22 index = value
  130. 22 index = index.clamp(dice_count * 1, dice_count * dice_type)
  131. 22 info = get_table_info(table, index)
  132. 22 text = "#{info.table_name}:#{info.value} > #{info.value}:#{info.body}"
  133. else
  134. else: 43
  135. 43 else: 8 case operator
  136. when: 16 when "+"
  137. 16 modify = value
  138. when: 19 when "-"
  139. 19 modify = value * -1
  140. end
  141. 43 dice_list = @randomizer.roll_barabara(dice_count, dice_type)
  142. 43 index += dice_list.sum
  143. 43 index += modify
  144. 43 index = index.clamp(dice_count * 1, dice_count * dice_type)
  145. 43 info = get_table_info(table, index)
  146. 43 then: 35 if modify != 0
  147. 35 text = "#{info.table_name}:#{dice_list.sum}[#{dice_list.join(',')}]#{operator}#{modify.abs} > #{info.value}:#{info.body}"
  148. else: 8 else
  149. 8 text = "#{info.table_name}:#{dice_list.sum}[#{dice_list.join(',')}] > #{info.value}:#{info.body}"
  150. end
  151. end
  152. 65 result.push(text)
  153. 65 return result
  154. end
  155. 1 def get_table_info(table, index)
  156. 92 info = table.choice(index)
  157. 92 return info
  158. end
  159. 1 def action_roll(command)
  160. 149 parser = Command::Parser.new("PP", round_type: round_type)
  161. .restrict_cmp_op_to(:>=, nil)
  162. .enable_critical
  163. .enable_fumble
  164. 149 cmd = parser.parse(command)
  165. 149 else: 17 then: 132 return nil unless cmd
  166. 17 cmd.critical ||= 12
  167. 17 cmd.fumble ||= 2
  168. 17 dice_list = @randomizer.roll_barabara(2, 6)
  169. 17 dice_total = dice_list.sum()
  170. 17 total = dice_total + cmd.modify_number
  171. result =
  172. 17 then: 5 if dice_total <= cmd.fumble
  173. 5 else: 12 Result.fumble("ファンブル(判定失敗。改変度を1D6点増加してバタフライエフェクト発生)")
  174. 12 then: 4 elsif dice_total >= cmd.critical
  175. 4 else: 8 Result.critical("スペシャル(判定成功。疲労度を1D6点減少してバタフライエフェクト発生)")
  176. 8 then: 1 elsif cmd.cmp_op.nil?
  177. 1 else: 7 Result.new
  178. 7 then: 4 elsif total >= cmd.target_number
  179. 4 Result.success("成功")
  180. else: 3 else
  181. 3 Result.failure("失敗")
  182. end
  183. sequence = [
  184. 17 "(#{cmd.to_s(:after_modify_number)})",
  185. "#{dice_total}[#{dice_list.join(',')}]#{Format.modifier(cmd.modify_number)}",
  186. total,
  187. result.text
  188. ].compact
  189. 17 result.text = sequence.join(" > ")
  190. 17 result
  191. end
  192. TABLES = {
  193. 1 'CT1' => DiceTable::D66Table.new(
  194. '原始時代経歴表',
  195. D66SortType::ASC,
  196. {
  197. 11 => '狩猟者',
  198. 12 => '石器職人',
  199. 13 => '毛皮職人',
  200. 14 => '骨加工職人',
  201. 15 => '木工職人',
  202. 16 => '木こり',
  203. 22 => '採集者',
  204. 23 => '法螺貝吹き',
  205. 24 => '集落の守り手',
  206. 25 => '食糧管理者',
  207. 26 => '石板職人',
  208. 33 => '部族戦士',
  209. 34 => '恐竜騎手',
  210. 35 => '恐竜学者',
  211. 36 => '恐竜飼育員',
  212. 44 => 'まじない師',
  213. 45 => '花摘み',
  214. 46 => '乱暴者',
  215. 55 => '族長',
  216. 56 => 'その日暮らし',
  217. 66 => '長老',
  218. }
  219. ),
  220. 'CT2' => DiceTable::D66Table.new(
  221. '古代経歴表',
  222. D66SortType::ASC,
  223. {
  224. 11 => '祭司',
  225. 12 => '陶工',
  226. 13 => '金細工職人',
  227. 14 => '貿易商',
  228. 15 => '墓守',
  229. 16 => '壁画画家',
  230. 22 => '哲学者',
  231. 23 => '彫刻家',
  232. 24 => '刻印師',
  233. 25 => 'ガラス職人',
  234. 26 => '粘土職人',
  235. 33 => '魔法研究者',
  236. 34 => '神官戦士',
  237. 35 => '木工職人',
  238. 36 => '踊り子',
  239. 44 => '予言者',
  240. 45 => '墓荒らし',
  241. 46 => 'カルト教祖',
  242. 55 => '超科学者',
  243. 56 => 'その日暮らし',
  244. 66 => '薬師',
  245. }
  246. ),
  247. 'CT3' => DiceTable::D66Table.new(
  248. '中世時代経歴表',
  249. D66SortType::ASC,
  250. {
  251. 11 => '農夫',
  252. 12 => '鍛冶屋',
  253. 13 => '商人',
  254. 14 => '宿屋の主人',
  255. 15 => '盗賊',
  256. 16 => '御者',
  257. 22 => '騎士・武士',
  258. 23 => '兵士・衛士',
  259. 24 => '錬金術師',
  260. 25 => '羊飼い',
  261. 26 => '音楽家',
  262. 33 => '貴族',
  263. 34 => '画家',
  264. 35 => '道化師',
  265. 36 => '町医者',
  266. 44 => '神職',
  267. 45 => '王族',
  268. 46 => '占い師',
  269. 55 => '魔術師',
  270. 56 => 'その日暮らし',
  271. 66 => '勇者',
  272. }
  273. ),
  274. 'CT4' => DiceTable::D66Table.new(
  275. '現代経歴表',
  276. D66SortType::ASC,
  277. {
  278. 11 => '医師',
  279. 12 => '弁護士',
  280. 13 => '教師',
  281. 14 => 'エンジニア',
  282. 15 => 'ミュージシャン',
  283. 16 => 'イラストレーター',
  284. 22 => '経営者',
  285. 23 => '秘書',
  286. 24 => 'パイロット',
  287. 25 => '銀行員',
  288. 26 => 'テレビマン',
  289. 33 => '営業',
  290. 34 => '作家',
  291. 35 => 'ジャーナリスト',
  292. 36 => '俳優',
  293. 44 => '警察官',
  294. 45 => '消防士',
  295. 46 => 'ギャンブラー',
  296. 55 => 'ギャング',
  297. 56 => 'その日暮らし',
  298. 66 => '学生',
  299. }
  300. ),
  301. 'CT5' => DiceTable::D66Table.new(
  302. '超情報化時代経歴表',
  303. D66SortType::ASC,
  304. {
  305. 11 => 'ブレードランナー',
  306. 12 => 'ドローンパイロット',
  307. 13 => 'ロボット工学者',
  308. 14 => 'データサイエンティスト',
  309. 15 => 'VRゲームデザイナー',
  310. 16 => '原子力工学技術者',
  311. 22 => 'AIエンジニア',
  312. 23 => '脳科学者',
  313. 24 => '環境工学エンジニア',
  314. 25 => 'セキュリティエンジニア',
  315. 26 => 'オペレーター',
  316. 33 => 'SNSインフルエンサー',
  317. 34 => 'プログラマ',
  318. 35 => 'ハードウェアエンジニア',
  319. 36 => 'ネットワークエンジニア',
  320. 44 => 'サイバネエンジニア',
  321. 45 => 'メガコーポ役員',
  322. 46 => '個人発信メディア運営',
  323. 55 => 'サイバーウェアドクター',
  324. 56 => 'その日暮らし',
  325. 66 => 'ハッカー',
  326. }
  327. ),
  328. 'CT6' => DiceTable::D66Table.new(
  329. '宇宙時代経歴表',
  330. D66SortType::ASC,
  331. {
  332. 11 => '宇宙飛行士',
  333. 12 => 'テラフォーミング技術者',
  334. 13 => '軌道エレベーターガール',
  335. 14 => '宇宙船メカニック',
  336. 15 => '宇宙物理学者',
  337. 16 => '超光速通信技術者',
  338. 22 => '恒星間密輸業者',
  339. 23 => 'ダークマター技術者',
  340. 24 => '宇宙警察',
  341. 25 => '宇宙ニンジャ',
  342. 26 => '銀河レーサー',
  343. 33 => '銀河の騎士',
  344. 34 => '銀河スパイ',
  345. 35 => '銀河行商人',
  346. 36 => '銀河放浪者',
  347. 44 => '元老院議員',
  348. 45 => '銀河帝国機動歩兵',
  349. 46 => '銀河皇帝',
  350. 55 => '賞金稼ぎ',
  351. 56 => 'その日暮らし',
  352. 66 => '宇宙海賊',
  353. }
  354. ),
  355. 'NMT1' => DiceTable::D66Table.new(
  356. '原始時代名前表(男性名)',
  357. D66SortType::ASC,
  358. {
  359. 11 => 'ドン',
  360. 12 => 'ヒュー',
  361. 13 => 'ゴロゴロ',
  362. 14 => 'ギュウ',
  363. 15 => 'バキ',
  364. 16 => 'カサカサ',
  365. 22 => 'ガッシャン',
  366. 23 => 'ピカ',
  367. 24 => 'モグモグ',
  368. 25 => 'ボロ',
  369. 26 => 'ドサ',
  370. 33 => 'ギラ',
  371. 34 => 'モクモク',
  372. 35 => 'ガチャ',
  373. 36 => 'ジュワ',
  374. 44 => 'ジャギン',
  375. 45 => 'ゴツン',
  376. 46 => 'ブル',
  377. 55 => 'ギュイン',
  378. 56 => 'ムチャ',
  379. 66 => 'ドデカーン',
  380. }
  381. ),
  382. 'NFT1' => DiceTable::D66Table.new(
  383. '原始時代名前表(女性名)',
  384. D66SortType::ASC,
  385. {
  386. 11 => 'パチン',
  387. 12 => 'プシュ',
  388. 13 => 'チラチラ',
  389. 14 => 'キャア',
  390. 15 => 'ペラ',
  391. 16 => 'サラサラ',
  392. 22 => 'クルクル',
  393. 23 => 'ハハ',
  394. 24 => 'パタパタ',
  395. 25 => 'ムニャ',
  396. 26 => 'クスクス',
  397. 33 => 'シーン',
  398. 34 => 'ピシャ',
  399. 35 => 'チク',
  400. 36 => 'サク',
  401. 44 => 'メラ',
  402. 45 => 'ジュルリ',
  403. 46 => 'ポチャ',
  404. 55 => 'ピリリ',
  405. 56 => 'ビビビ',
  406. 66 => 'モフ',
  407. }
  408. ),
  409. 'NMT2' => DiceTable::D66Table.new(
  410. '古代名前表(男性名)',
  411. D66SortType::ASC,
  412. {
  413. 11 => 'クフ',
  414. 12 => 'アメンホテプ',
  415. 13 => 'セティ',
  416. 14 => 'ホレムヘブ',
  417. 15 => 'ネフェルカレ',
  418. 16 => 'サルゴン',
  419. 22 => 'ハンムラビ',
  420. 23 => 'ナボニドゥス',
  421. 24 => 'アシュール・ナシル',
  422. 25 => 'ネルガル',
  423. 26 => 'キニチ・ジャナーブ',
  424. 33 => 'ジャサウ・チャン',
  425. 34 => 'バラム',
  426. 35 => 'ワクサクラフーン',
  427. 36 => 'アトラノス',
  428. 44 => 'ポセイドニス',
  429. 45 => 'アクアリオン',
  430. 46 => 'アトランテオス',
  431. 55 => 'ゼファイロス',
  432. 56 => 'オーシャナス',
  433. 66 => 'サラッソス',
  434. }
  435. ),
  436. 'NFT2' => DiceTable::D66Table.new(
  437. '古代名前表(女性名)',
  438. D66SortType::ASC,
  439. {
  440. 11 => 'イシス',
  441. 12 => 'ティエ',
  442. 13 => 'メルネイト',
  443. 14 => 'サティア',
  444. 15 => 'ネフェルティティ',
  445. 16 => 'アタリヤ',
  446. 22 => 'ナキア',
  447. 23 => 'シブトゥ',
  448. 24 => 'プアビ',
  449. 25 => 'クババ',
  450. 26 => 'ワク',
  451. 33 => 'ヨク',
  452. 34 => 'タキエン',
  453. 35 => 'イシュチャック',
  454. 36 => 'サラッサ',
  455. 44 => 'トリトニア',
  456. 45 => 'ラディアンティア',
  457. 46 => 'アトランティア',
  458. 55 => 'ムアナ',
  459. 56 => 'オリカルシア',
  460. 66 => 'サフィラ',
  461. }
  462. ),
  463. 'NLT2' => DiceTable::D66Table.new(
  464. '古代名前表(姓)',
  465. D66SortType::ASC,
  466. {
  467. 11 => 'なし',
  468. 12 => 'なし',
  469. 13 => 'なし',
  470. 14 => 'なし',
  471. 15 => 'なし',
  472. 16 => 'なし',
  473. 22 => 'なし',
  474. 23 => 'なし',
  475. 24 => 'パル',
  476. 25 => 'ウセジブ',
  477. 26 => 'パカル',
  478. 33 => 'カウィル',
  479. 34 => 'アジャウ',
  480. 35 => 'チャパット',
  481. 36 => 'なし',
  482. 44 => 'なし',
  483. 45 => 'なし',
  484. 46 => 'なし',
  485. 55 => 'なし',
  486. 56 => 'なし',
  487. 66 => 'なし',
  488. }
  489. ),
  490. 'NMT3' => DiceTable::D66Table.new(
  491. '中世時代(日本)名前表(男性名)',
  492. D66SortType::ASC,
  493. {
  494. 11 => '九郎右衛門',
  495. 12 => '弥太郎',
  496. 13 => '光太夫(こうだゆう)',
  497. 14 => '十兵衛',
  498. 15 => '五十六',
  499. 16 => '雪道',
  500. 22 => '義元',
  501. 23 => '長政',
  502. 24 => '清正',
  503. 25 => '政秀',
  504. 26 => '隆盛',
  505. 33 => '田三郎',
  506. 34 => '晋作',
  507. 35 => '鉄舟(てっしゅう)',
  508. 36 => '昌幸',
  509. 44 => '武蔵',
  510. 45 => '親蓮(しんれん)',
  511. 46 => '澄海(せいかい)',
  512. 55 => '法鸞(ほうらん)',
  513. 56 => '少林(しょうりん)',
  514. 66 => '鑑禅(かんぜん)',
  515. }
  516. ),
  517. 'NFT3' => DiceTable::D66Table.new(
  518. '中世時代(日本)名前表(女性名)',
  519. D66SortType::ASC,
  520. {
  521. 11 => '静(しず)',
  522. 12 => '市(いち)',
  523. 13 => '初(はつ)',
  524. 14 => '春(はる)',
  525. 15 => '鶴(つる)',
  526. 16 => 'とき',
  527. 22 => 'しの',
  528. 23 => '光(みつ)',
  529. 24 => 'ゆき',
  530. 25 => '京(きょう)',
  531. 26 => 'すず',
  532. 33 => 'さよ',
  533. 34 => 'とせ',
  534. 35 => 'とよ',
  535. 36 => '幸(さち)',
  536. 44 => '琴(こと)',
  537. 45 => '美濃(みの)',
  538. 46 => '千(せん)',
  539. 55 => '松(まつ)',
  540. 56 => '淀(よど)',
  541. 66 => '月(つき)',
  542. }
  543. ),
  544. 'NLT3' => DiceTable::D66Table.new(
  545. '中世時代(日本)名前表(姓)',
  546. D66SortType::ASC,
  547. {
  548. 11 => '石田',
  549. 12 => '今川',
  550. 13 => '上杉',
  551. 14 => '武田',
  552. 15 => '大友',
  553. 16 => '真田',
  554. 22 => '北条',
  555. 23 => '宮本',
  556. 24 => '山岡',
  557. 25 => '井伊',
  558. 26 => '柳生',
  559. 33 => '樋口',
  560. 34 => '本間',
  561. 35 => '尾高',
  562. 36 => '大黒屋',
  563. 44 => '森',
  564. 45 => 'なし',
  565. 46 => 'なし',
  566. 55 => 'なし',
  567. 56 => 'なし',
  568. 66 => 'なし',
  569. }
  570. ),
  571. 'NMT3W' => DiceTable::D66Table.new(
  572. '中世時代(西洋)名前表(男性名)',
  573. D66SortType::ASC,
  574. {
  575. 11 => 'ソルガー',
  576. 12 => 'アルデン',
  577. 13 => 'エイモン',
  578. 14 => 'ヴァリス',
  579. 15 => 'ロリック',
  580. 16 => 'セイン',
  581. 22 => 'エルリック',
  582. 23 => 'オズリック',
  583. 24 => 'ジャレス',
  584. 25 => 'エレンディル',
  585. 26 => 'エルドレッド',
  586. 33 => 'エリック',
  587. 34 => 'ケルドーン',
  588. 35 => 'ダーリン',
  589. 36 => 'ラダガスト',
  590. 44 => 'ダゴン',
  591. 45 => 'エッダード',
  592. 46 => 'アラン',
  593. 55 => 'ジハード',
  594. 56 => 'ライアン',
  595. 66 => 'バルバトス',
  596. }
  597. ),
  598. 'NFT3W' => DiceTable::D66Table.new(
  599. '中世時代(西洋)名前表(女性名)',
  600. D66SortType::ASC,
  601. {
  602. 11 => 'セラフィン',
  603. 12 => 'エリシア',
  604. 13 => 'エララ',
  605. 14 => 'ミリ',
  606. 15 => 'アルテア',
  607. 16 => 'サリエル',
  608. 22 => 'アストリッド',
  609. 23 => 'エルウィン',
  610. 24 => 'モルガナ',
  611. 25 => 'シルヴァ',
  612. 26 => 'タリア',
  613. 33 => 'オデッサ',
  614. 34 => 'カサンドラ',
  615. 35 => 'アイリス',
  616. 36 => 'ガラドリエル',
  617. 44 => 'ダフネ',
  618. 45 => 'ネリダ',
  619. 46 => 'ルーシェン',
  620. 55 => 'フィオラ',
  621. 56 => 'キーラ',
  622. 66 => 'エリノラ',
  623. }
  624. ),
  625. 'NLT3W' => DiceTable::D66Table.new(
  626. '中世時代(西洋)名前表(姓)',
  627. D66SortType::ASC,
  628. {
  629. 11 => 'アイアンハンド',
  630. 12 => 'ストームライダー',
  631. 13 => 'ウィンドウォーカー',
  632. 14 => 'シャドウクローク',
  633. 15 => 'ドラゴンベイン',
  634. 16 => 'アースシェイカー',
  635. 22 => 'ウルフハート',
  636. 23 => 'ハンマーフィスト',
  637. 24 => 'ベアクロー',
  638. 25 => 'フロストビアード',
  639. 26 => 'ストームフォージ',
  640. 33 => 'ムーンシャドウ',
  641. 34 => 'スターウィスパー',
  642. 35 => 'ストームダンサー',
  643. 36 => 'ライトフット',
  644. 44 => 'スターフォール',
  645. 45 => 'ムーンビーム',
  646. 46 => 'ホワイトソーン',
  647. 55 => 'なし',
  648. 56 => 'なし',
  649. 66 => 'なし',
  650. }
  651. ),
  652. 'NMT4' => DiceTable::D66Table.new(
  653. '現代(日本)名前表(男性名)',
  654. D66SortType::ASC,
  655. {
  656. 11 => '明',
  657. 12 => '隆',
  658. 13 => '優',
  659. 14 => '謙',
  660. 15 => '直樹',
  661. 16 => '真一',
  662. 22 => '健一',
  663. 23 => '純一',
  664. 24 => '良太',
  665. 25 => '達也',
  666. 26 => '悠',
  667. 33 => '龍一',
  668. 34 => '一真',
  669. 35 => '虎之介',
  670. 36 => '流星',
  671. 44 => '慎之介',
  672. 45 => '大和',
  673. 46 => '大輝',
  674. 55 => '瑛人',
  675. 56 => '義人',
  676. 66 => '海斗',
  677. }
  678. ),
  679. 'NFT4' => DiceTable::D66Table.new(
  680. '現代(日本)名前表(女性名)',
  681. D66SortType::ASC,
  682. {
  683. 11 => '麻美',
  684. 12 => '美紀',
  685. 13 => '真理子',
  686. 14 => '香織',
  687. 15 => '美穂',
  688. 16 => '恵美',
  689. 22 => '佳子',
  690. 23 => '雅子',
  691. 24 => '真由美',
  692. 25 => '彩',
  693. 26 => '千沙',
  694. 33 => '菜々子',
  695. 34 => '真理',
  696. 35 => '桜',
  697. 36 => '美月',
  698. 44 => '美優',
  699. 45 => '麗華',
  700. 46 => '真緒',
  701. 55 => '陽菜',
  702. 56 => '聖華',
  703. 66 => '愛梨',
  704. }
  705. ),
  706. 'NLT4' => DiceTable::D66Table.new(
  707. '現代(日本)名前表(姓)',
  708. D66SortType::ASC,
  709. {
  710. 11 => '佐藤',
  711. 12 => '鈴木',
  712. 13 => '高橋',
  713. 14 => '田中',
  714. 15 => '渡辺',
  715. 16 => '伊藤',
  716. 22 => '山本',
  717. 23 => '中村',
  718. 24 => '小林',
  719. 25 => '吉田',
  720. 26 => '山田',
  721. 33 => '佐々木',
  722. 34 => '斎藤',
  723. 35 => '木村',
  724. 36 => '長谷部',
  725. 44 => '井上',
  726. 45 => '山口',
  727. 46 => '藤井',
  728. 55 => '櫻井',
  729. 56 => '百瀬',
  730. 66 => '十文字',
  731. }
  732. ),
  733. 'NMT4W' => DiceTable::D66Table.new(
  734. '現代(西洋)名前表(男性名)',
  735. D66SortType::ASC,
  736. {
  737. 11 => 'ジェームズ',
  738. 12 => 'ジョン',
  739. 13 => 'ロバート',
  740. 14 => 'マイケル',
  741. 15 => 'ウィリアム',
  742. 16 => 'デイビッド',
  743. 22 => 'リチャード',
  744. 23 => 'ジョセフ',
  745. 24 => 'トーマス',
  746. 25 => 'チャールズ',
  747. 26 => 'クリストファー',
  748. 33 => 'ダニエル',
  749. 34 => 'マシュー',
  750. 35 => 'マーク',
  751. 36 => 'ポール',
  752. 44 => 'スティーブン',
  753. 45 => 'アンドリュー',
  754. 46 => 'ジョシュア',
  755. 55 => 'レオナルド',
  756. 56 => 'マクシマス',
  757. 66 => 'マーティ',
  758. }
  759. ),
  760. 'NFT4W' => DiceTable::D66Table.new(
  761. '現代(西洋)名前表(女性名)',
  762. D66SortType::ASC,
  763. {
  764. 11 => 'メアリー',
  765. 12 => 'ジェニファー',
  766. 13 => 'リンダ',
  767. 14 => 'パトリシア',
  768. 15 => 'エリザベス',
  769. 16 => 'スーザン',
  770. 22 => 'ジェシカ',
  771. 23 => 'サラ',
  772. 24 => 'カレン',
  773. 25 => 'ナンシー',
  774. 26 => 'リサ',
  775. 33 => 'マーガレット',
  776. 34 => 'ベティ',
  777. 35 => 'サンドラ',
  778. 36 => 'アシュリー',
  779. 44 => 'ドロシー',
  780. 45 => 'キム',
  781. 46 => 'エミリー',
  782. 55 => 'ドナ',
  783. 56 => 'ミシェル',
  784. 66 => 'ジェニファー',
  785. }
  786. ),
  787. 'NLT4W' => DiceTable::D66Table.new(
  788. '現代(西洋)名前表(姓)',
  789. D66SortType::ASC,
  790. {
  791. 11 => 'スミス',
  792. 12 => 'ジョンソン',
  793. 13 => 'ウィリアムズ',
  794. 14 => 'ブラウン',
  795. 15 => 'ジョーンズ',
  796. 16 => 'ミラー',
  797. 22 => 'デイビス',
  798. 23 => 'マルティネス',
  799. 24 => 'ロドリゲス',
  800. 25 => 'ウィルソン',
  801. 26 => 'リーブ',
  802. 33 => 'ムーア',
  803. 34 => 'ジャクソン',
  804. 35 => 'トンプソン',
  805. 36 => 'アンダーソン',
  806. 44 => 'テイラー',
  807. 45 => 'マーチン',
  808. 46 => 'ホワイト',
  809. 55 => 'ハリス',
  810. 56 => 'ジョイ',
  811. 66 => 'マクフライ',
  812. }
  813. ),
  814. 'NMT5' => DiceTable::D66Table.new(
  815. '超情報化時代名前表(男性名)',
  816. D66SortType::ASC,
  817. {
  818. 11 => 'ゼファー',
  819. 12 => 'オリオン',
  820. 13 => 'カシウス',
  821. 14 => 'アトラス',
  822. 15 => 'シリウス',
  823. 16 => 'ソル',
  824. 22 => 'ドラコ',
  825. 23 => 'ヴェガ',
  826. 24 => 'マーキュリー',
  827. 25 => 'ハレー',
  828. 26 => 'リゲル',
  829. 33 => 'アスター',
  830. 34 => 'クェーサー',
  831. 35 => 'ノヴァ',
  832. 36 => 'ヘリオス',
  833. 44 => 'ゲイレン',
  834. 45 => 'ネビュラ',
  835. 46 => 'パルサー',
  836. 55 => 'トーラス',
  837. 56 => 'ファン',
  838. 66 => 'ヨリノブ',
  839. }
  840. ),
  841. 'NFT5' => DiceTable::D66Table.new(
  842. '超情報化時代名前表(女性名)',
  843. D66SortType::ASC,
  844. {
  845. 11 => 'リラ',
  846. 12 => 'ヴィーナス',
  847. 13 => 'アウロラ',
  848. 14 => 'ステラ',
  849. 15 => 'セレネ',
  850. 16 => 'ヴェラ',
  851. 22 => 'ジルナ',
  852. 23 => 'ヴェガ',
  853. 24 => 'セレスト',
  854. 25 => 'クリサンセマ',
  855. 26 => 'フクシア',
  856. 33 => 'サファイア',
  857. 34 => 'アザレア',
  858. 35 => 'ノヴァ',
  859. 36 => 'ベゴニア',
  860. 44 => 'カメリア',
  861. 45 => 'マグノリア',
  862. 46 => 'ハイビス',
  863. 55 => 'フリージア',
  864. 56 => 'マリーゴールド',
  865. 66 => 'ハナコ',
  866. }
  867. ),
  868. 'NLT5' => DiceTable::D66Table.new(
  869. '超情報化時代名前表(姓)',
  870. D66SortType::ASC,
  871. {
  872. 11 => 'ヤマモト',
  873. 12 => 'ンコシ',
  874. 13 => 'パテル',
  875. 14 => 'ジェン',
  876. 15 => 'クリシュナン',
  877. 16 => 'シン',
  878. 22 => 'タボ',
  879. 23 => 'ワン',
  880. 24 => 'クォン',
  881. 25 => 'ウー',
  882. 26 => 'ウォン',
  883. 33 => 'ミヤザキ',
  884. 34 => 'ファン',
  885. 35 => 'セロン',
  886. 36 => 'バティア',
  887. 44 => 'スズキ',
  888. 45 => 'ホー',
  889. 46 => 'ウィズ',
  890. 55 => 'カウル',
  891. 56 => 'グプタ',
  892. 66 => 'アラサカ',
  893. }
  894. ),
  895. 'NMT6' => DiceTable::D66Table.new(
  896. '宇宙時代名前表(男性名)',
  897. D66SortType::ASC,
  898. {
  899. 11 => 'アルタイア',
  900. 12 => 'コメット',
  901. 13 => 'フェニックス',
  902. 14 => 'アストラ',
  903. 15 => 'ソラス',
  904. 16 => 'スタリオン',
  905. 22 => 'スカイゲイザー',
  906. 23 => 'ハイペリオン',
  907. 24 => 'ソラリウス',
  908. 25 => 'プラズマ',
  909. 26 => 'スペクトル',
  910. 33 => 'クラスター',
  911. 34 => 'ヴォイド',
  912. 35 => 'アストロノーム',
  913. 36 => 'インフィニティ',
  914. 44 => 'スパイラル',
  915. 45 => 'センチュリオン',
  916. 46 => 'パラダイム',
  917. 55 => 'スターフィールド',
  918. 56 => 'ニュートロン',
  919. 66 => 'メテオライト',
  920. }
  921. ),
  922. 'NFT6' => DiceTable::D66Table.new(
  923. '宇宙時代名前表(女性名)',
  924. D66SortType::ASC,
  925. {
  926. 11 => 'カシオペア',
  927. 12 => 'ルナ',
  928. 13 => 'ソラナ',
  929. 14 => 'アンドラ',
  930. 15 => 'ギャレナ',
  931. 16 => 'セレスティア',
  932. 22 => 'スターライト',
  933. 23 => 'ガラクシア',
  934. 24 => 'メテオラ',
  935. 25 => 'エクリプス',
  936. 26 => 'ルナリス',
  937. 33 => 'サテライト',
  938. 34 => 'プレアデス',
  939. 35 => 'サンフラワー',
  940. 36 => 'ホライゾン',
  941. 44 => 'フェノメナ',
  942. 45 => 'アストリッド',
  943. 46 => 'ミレニアム',
  944. 55 => 'ヴォルテックス',
  945. 56 => 'フュージョン',
  946. 66 => 'マトリクス',
  947. }
  948. ),
  949. 'NLT6' => DiceTable::D66Table.new(
  950. '宇宙時代名前表(姓)',
  951. D66SortType::ASC,
  952. {
  953. 11 => 'スターボーン',
  954. 12 => 'ネブラ',
  955. 13 => 'ギャラクソス',
  956. 14 => 'オリオニス',
  957. 15 => 'スターウィーバー',
  958. 16 => 'ライトイヤー',
  959. 22 => 'スターダスト',
  960. 23 => 'スカイドリーム',
  961. 24 => 'ギャラクシオン',
  962. 25 => 'スターファイア',
  963. 26 => 'ラプソディ',
  964. 33 => 'アポロ',
  965. 34 => 'ガリレオ',
  966. 35 => 'オービット',
  967. 36 => 'ステラート',
  968. 44 => 'アストラル',
  969. 45 => 'シグマ',
  970. 46 => 'アーク',
  971. 55 => 'オメガ',
  972. 56 => 'エンデバー',
  973. 66 => 'リープ',
  974. }
  975. ),
  976. 'CTT' => DiceTable::D66Table.new(
  977. '因縁種別表(因縁種別/因縁強度)',
  978. D66SortType::ASC,
  979. {
  980. 11 => '実の父・母/6',
  981. 12 => '養父・養母/4',
  982. 13 => '養子/4',
  983. 14 => 'ペット/4',
  984. 15 => '親友/3',
  985. 16 => '友人/2',
  986. 22 => '実の兄弟・姉妹/6',
  987. 23 => '義理の兄弟・姉妹/4',
  988. 24 => '同僚/3',
  989. 25 => '隣人/1',
  990. 26 => 'お客さんor君のファン/1',
  991. 33 => '実の祖父母/5',
  992. 34 => 'クラスメイト/2',
  993. 35 => '先輩/2',
  994. 36 => '後輩/2',
  995. 44 => '実の子/6',
  996. 45 => '上司or師/3',
  997. 46 => '部下or生徒/3',
  998. 55 => '異性の配偶者/5',
  999. 56 => '同性の配偶者/4',
  1000. 66 => '恋人/3',
  1001. }
  1002. ),
  1003. }.freeze
  1004. TABLES_MOD_2D = {
  1005. 1 'ACT' => DiceTable::Table.new(
  1006. 'アクシデント表',
  1007. '2D6',
  1008. [
  1009. '一匹の蝶の羽ばたきが、地球の裏側では竜巻を巻き起こす。あなたは目の前にある他愛のない何かを拾って、置き直した。GMはランダムに指定特技を決定する。シーンに登場しているPCは全員その指定特技で判定する。判定に成功すれば何も起こらない。判定に失敗すると自分を対象としてバタフライエフェクトが発生する。その際の対象の因縁強度は6として処理する。',
  1010. '目の前で大事故が発生する。事故に巻き込まれた人を助けなければ。シーンプレイヤーのPCは《医療》《労働》《持ち上げる》《倫理》《応急処置》《魔除け》のいずれかを指定特技として判定を行う。判定に成功すると、目の前の人を助けることができる。PCの[疲労度]が1D6点減少する。だがその人物は本来はここで死ぬべき運命だったようだ。自分の【因縁】からランダムに選んだキャラクターを対象としてバタフライエフェクトが発生する。判定に失敗するとPCの[疲労度]が1D6点増加する。',
  1011. 'あなたの出身時代では知りえない情報を知ってしまう。その情報をあなたが覚えている限り歴史に重大な影響をもたらすだろう。シーンプレイヤーのPCは《記憶力》の判定を行う。判定に失敗すると自分の【因縁】のうちの好きなキャラクターを対象としてバタフライエフェクトが発生する。',
  1012. '誰かと出会い頭に衝突しそうになる。シーンプレイヤーは舞台となっている時代の名前表と経歴表を使用し、年齢は8D6を振って、相手の設定概要を決める。TAはその相手の設定に従って、最適な指定特技を決定する。シーンプレイヤーのPCはその指定特技で判定を行う。判定に失敗すると、相手とぶつかってしまい、シーンプレイヤーのPCの[改変度]が1D6増加する。',
  1013. '困っている人がいる。シーンプレイヤーは舞台となっている時代の名前表と経歴表を使用し、年齢は8D6を振って、相手の設定概要を決める。TAはその相手の設定に従って、最適な指定特技を決定する。シーンプレイヤーのPCはその指定特技で判定を行う。判定に成功すれば、[改変度]が1点増加しつつも困りごとを解決してあげることができる。シーンプレイヤーのPCはお礼として好きな【アイテム】1つを獲得する。',
  1014. 'シーンプレイヤーは好きなPCを登場させることができる。そしてシーンプレイヤーはシーンに登場しているキャラクター一人を選び、二人で何かしらひと時を過ごす。シーンプレイヤーのPCは好きな指定特技で判定を行う。判定に成功すれば、選んだキャラクターを新たな【因縁】として獲得できる。相手のPCもシーンプレイヤーのPCを新たな【因縁】として獲得できる。因縁種別は「タイムトラベル仲間/因縁強度6」となる。因縁内容は状況にふさわしいものをポジティブ因縁内容表もしくはネガティブ因縁内容表から選択する。',
  1015. '運命的な出会い。シーンプレイヤーのPCは好きな指定特技で判定を行う。判定に成功すれば、シーンプレイヤーはセッションの舞台となっている時代/ELの新たな【因縁】を獲得する。因縁内容表を用いて【因縁】を作成する。1D6を振って奇数が出ればポジティブ因縁内容表、偶数が出ればネガティブ因縁内容表を使用する。ただし因縁種別は「親友/因縁強度3」もしくは「恋人/因縁強度4」のいずれかから選択する。細かい設定は名前表や経歴表を振って決めること。',
  1016. '遠く離れて、思い起こされる人物。シーンプレイヤーのPCは好きな指定特技で判定を行う。判定に成功すれば、自分の出身時代/ELの新たな【因縁】を獲得する。初期作成時と同じく、因縁種別表と因縁内容表を用いて【因縁】を作成する。1D6を振って奇数が出ればポジティブ因縁内容表、偶数が出ればネガティブ因縁内容表を使用する。細かい設定は名前表や経歴表を振って決めること。',
  1017. 'シーンプレイヤーは好きなPCを登場させることができる。宇宙開闢の女神があなたに微笑みかける。これを成功させれば歴史改変を修正できる、という理路が導き出される。シーンプレイヤーのPCはランダムに決定した指定特技の判定を行う。判定に成功すれば、登場しているPCのうち好きな一人の[改変度]が1D6点減少する。',
  1018. 'シーンプレイヤーは好きなPCを登場させることができる。この時代にも心を落ち着けることができる場所を見つけることができた。何をして疲れを癒そう。シーンプレイヤーのPCはランダムに決定した指定特技で判定を行う。判定に成功すれば、シーンに登場しているPC全員の[疲労度]が1D6点減少する。',
  1019. 'シーンプレイヤーは好きなPCを登場させることができる。宇宙開闢の女神があなたたちを抱擁する。これを成功させれば大幅に歴史改変を修正できる、という理路が導き出される。シーンプレイヤーのPCはランダムに決定した指定特技の判定を行う。判定に成功すれば、シーンに登場しているPC全員の[改変度]が1D6点減少する。'
  1020. ]
  1021. ),
  1022. 'ST4' => DiceTable::Table.new(
  1023. '現代シーン表',
  1024. '2D6',
  1025. [
  1026. '鳴り響く雷鳴と土砂降りの雨。嵐の路地でなすべきことをしろ。',
  1027. 'その地域の有名観光地。旅行者たちが自撮りにいそしんでいる。気楽なものだ。',
  1028. 'ブロックバスター映画のポスターが飾られた映画館。この時代の文化を知るには役に立つだろうか。',
  1029. 'ノートPCを開く人々でひしめき合う、有名コーヒーチェーン店。ひとまず落ち着こう。焦ってもいいことはない。',
  1030. '古びた公園。撤去された遊具の支柱だけがさびたままに放置されており、少し寂しげだ。',
  1031. '駅前のショッピングビル。この建物だけで欲しいものが全て手に入る。なんて便利な時代なんだ。',
  1032. '鮮やかなネオンが照らす夜の繁華街。若者たちが新型の携帯通信端末を振り回しながら往来している。この時代が平和な証拠だろう。',
  1033. '様々なテナントが軒を連ねる大型ショッピングモール。物質にあふれたこの時代に心の安らぎはあるのか。',
  1034. 'ヴィーガンメニューが並ぶスタイリッシュなレストラン。野菜だけを食べる習慣。この時代に流行りの多様性ってやつか。',
  1035. '旅行者で賑わう空港のラウンジ。離着陸する飛行機は流体力学を利用した単純な作りだが、安全性は高いらしい。',
  1036. 'おだやかな風が通り抜ける。自然あふれるこんな場所も、この時代にあったのだな。'
  1037. ]
  1038. ),
  1039. 'TT' => DiceTable::Table.new(
  1040. 'タイムトラベル演出表',
  1041. '2D6',
  1042. [
  1043. '科学者の実験で発生した七色の光を浴びてしまい、あなたの身体は分解され、違う時代で再構成された。',
  1044. '科学者が作った物の大きさを自在に変化させる量子物質に触れてしまい、あなたの体は微小レベルまで縮んでしまった。量子世界をしばらくさまよったあと、運よく元の大きさに戻れたが別の時代へと移動してしまっていた。',
  1045. 'あなたは偶然手に入れた腕時計を気まぐれで腕に装着した。時刻を合わせようとをリューズを回すと、時空にゆがみが生じ、タイムトラベルしてしまった。腕時計はその力を使い果たし粉々にくだけた。',
  1046. 'あなたの乗った乗物が突如超高速で走り始めた。それは光速に近づきつつあった。いや、すでに光速を超えているかもしれない。光速に限りなく近い速度なら未来に、光速を超えたスピードなら過去に移動してしまうだろう。',
  1047. '科学者が試乗をしてくれというので、乗り込んだ車が怪しげなメカが搭載されたタイムマシンだった。帰りの分の燃料は当然ない。',
  1048. '雷に打たれ、気を失った。そして目を覚ますと、あなたがもといた時代とは、違う時代へ来てしまっていた。',
  1049. 'あなたの目の前に偶然ワームホールが出現する。ワームホールから放たれる引力には抗えず、あなたは時空を超えてしまう。',
  1050. '緑色に光る怪しげな石を見つけたあなたは、その美しさに魅入られてしまう。どれくらい時がたっただろうか。気づけはあなたは違う時代にいた。',
  1051. '偶然手に入れた謎の書物に書かれた呪文を読み上げた瞬間、あなたの身体は光に包まれ、違う時代へと転送されてしまった。',
  1052. 'あなたは黒ずくめの服を着た謎の組織に拘束され、怪しげなクスリを飲まされてしまった。気づけばそこは違う時代だった。',
  1053. '自宅の机の引き出しを開けると、そこは混沌の空間が広がっていた。青い腕の先についた指のない白い手があなたを掴み(指がないにも関わらず、だ)、怪しげな板にあなたを乗せた。正体不明の青いずんぐりとしたフォルムの存在はその板に設置された操縦桿を操り、混沌の中を進んだ。しばらくしてあなたはもといた時代とは全く別の場所へ放り出された。'
  1054. ]
  1055. ),
  1056. }.freeze
  1057. TABLES_MOD_1D = {
  1058. 1 'RT' => DiceTable::Table.new(
  1059. '帰還演出表',
  1060. '1D6',
  1061. [
  1062. 'この時代に来た方法と同じ演出で帰還できる。',
  1063. 'この時代に来た方法と同じ演出で帰還できる。',
  1064. 'この時代に来た方法と同じ演出で帰還できる。',
  1065. '少し目を閉じて、故郷へ想いを馳せる。眼を開けると懐かしい景色が広がっている。元の時代へ戻って来たのだ。',
  1066. '目の前の空間に別時代へのポータルが開く。それをくぐればあなたの住んでいた元の時代だ。',
  1067. '天から神々しい光が降りそそぐ。宇宙開闢の女神が微笑みかけると、あなたは強い光に包まれる。その光はあなたを元の時代へと導く。',
  1068. ]
  1069. ),
  1070. 'CPT' => DiceTable::Table.new(
  1071. 'ポジティブ因縁内容表',
  1072. '1D6',
  1073. [
  1074. '共存。一緒にいて自然な関係だ。',
  1075. '互助。つらい時にはいつでもそばにいた。',
  1076. '同志。共に道を歩むかけがえのない仲間だ。',
  1077. '片愛。あなたは、相手のことが大好きだ。',
  1078. '相愛。お互いのことが大好きだ。',
  1079. '理解。何も言わなくても相手のことならなんでもわかる。',
  1080. ]
  1081. ),
  1082. 'CNT' => DiceTable::Table.new(
  1083. 'ネガティブ因縁内容表',
  1084. '1D6',
  1085. [
  1086. '邪魔。なぜかいつも視界の端にいる。',
  1087. '不快。一緒にいるとちょっとイラつく。',
  1088. '厄介。関わりたくもないのに、いつもちょっかいを出してくる。',
  1089. '嫌悪。やることなすことすべてが気に食わない。',
  1090. '憎悪。過去の恨みか、激しい感情を持っている。',
  1091. '天敵。不倶戴天の敵、いつでも対立して喧嘩ばかりしている。',
  1092. ]
  1093. ),
  1094. 'IT' => DiceTable::Table.new(
  1095. 'アイテム決定表',
  1096. '1D6',
  1097. [
  1098. '癒しの品。いつでも使用可能。好きなキャラクター(自身含む)の[疲労度]を1D6点減少させることができる。使用すると失われる。',
  1099. '癒しの品。いつでも使用可能。好きなキャラクター(自身含む)の[疲労度]を1D6点減少させることができる。使用すると失われる。',
  1100. '幸運の品。誰か(自身含む)の判定のサイコロを振った直後に使用可能。自身の[改変度]を1点増加すれば、その判定にプラス1の修正をつけることができる。使用すると失われる。',
  1101. '幸運の品。誰か(自身含む)の判定のサイコロを振った直後に使用可能。自身の[改変度]を1点増加すれば、その判定にプラス1の修正をつけることができる。使用すると失われる。',
  1102. '運命の品。誰か(自身含む)がシステムおよびシナリオで用意された表を使用してダイスを振った直後に使用可能。ダイスの結果を±1ずらすことができる。ただしその表に設定されていない値にずらすことはできない。使用すると失われる。',
  1103. '運命の品。誰か(自身含む)がシステムおよびシナリオで用意された表を使用してダイスを振った直後に使用可能。ダイスの結果を±1ずらすことができる。ただしその表に設定されていない値にずらすことはできない。使用すると失われる。',
  1104. ]
  1105. ),
  1106. 'AGT' => DiceTable::Table.new(
  1107. '時代決定表',
  1108. '1D6',
  1109. [
  1110. '原始時代/EL1',
  1111. '古代/EL2',
  1112. '中世時代/EL3',
  1113. '現代/EL4',
  1114. '超情報化時代/EL5',
  1115. '宇宙時代/EL6',
  1116. ]
  1117. ),
  1118. }.freeze
  1119. TABLES_MOD_MINUS = {
  1120. 1 'SBET' => DiceTable::Table.new(
  1121. '重度バタフライエフェクト表',
  1122. '2D6',
  1123. [
  1124. '消失。対象の存在自体が時空連続体から完全に消失する。対象を【因縁】としていた全てのPCはその【因縁】の消失欄にチェックを入れ、その対象との【因縁】内容がネガティブなら[疲労度]が「対象の因縁強度+3」点減少、ポジティブなら[疲労度]と[改変度]が「対象の因縁強度+3」点ずつ増加する。',
  1125. '消失。対象の存在自体が時空連続体から完全に消失する。対象を【因縁】としていた全てのPCはその【因縁】の消失欄にチェックを入れ、その対象との【因縁】内容がネガティブなら[疲労度]が「対象の因縁強度+3」点減少、ポジティブなら[疲労度]と[改変度]が「対象の因縁強度+3」点ずつ増加する。',
  1126. '消失の可能性。対象の存在自体があいまいになってしまう。表をふったプレイヤーはランダムに選んだ特技を指定特技として判定する。判定に失敗すると対象の存在は消失する。対象を【因縁】としていた全てのPCは対象の【因縁】の消失欄にチェックを入れ、その対象との因縁内容がネガティブなら[疲労度]が「対象の因縁強度+2」点減少、ポジティブなら[疲労度]と[改変度]が「対象の因縁強度+2」点ずつ増加する。',
  1127. '消失の可能性。対象の存在自体があいまいになってしまう。表をふったプレイヤーはランダムに選んだ特技を指定特技として判定する。判定に失敗すると対象の存在は消失する。対象を【因縁】としていた全てのPCは対象の【因縁】の消失欄にチェックを入れ、その対象との因縁内容がネガティブなら[疲労度]が「対象の因縁強度+2」点減少、ポジティブなら[疲労度]と[改変度]が「対象の因縁強度+2」点ずつ増加する。',
  1128. '時代変更。対象の存在している時代が変わってしまう。存在する時代が変わってしまえば、もはやPCのことは覚えていないだろう。表を振ったプレイヤーは時代決定表を振って、変更先の時代を決定する。現在と同じ時代となれば、何も起こらない。違う時代になってしまったら、対象を【因縁】としていた全てのPCは対象の【因縁】の消失欄にチェックを入れ、その対象との因縁内容がネガティブなら[疲労度]が「対象の因縁強度+1」点減少、ポジティブなら[疲労度]と[改変度]が「対象の因縁強度+1」点ずつ増加する。',
  1129. '時代変更。対象の存在している時代が変わってしまう。存在する時代が変わってしまえば、もはやPCのことは覚えていないだろう。表を振ったプレイヤーは時代決定表を振って、変更先の時代を決定する。現在と同じ時代となれば、何も起こらない。違う時代になってしまったら、対象を【因縁】としていた全てのPCは対象の【因縁】の消失欄にチェックを入れ、その対象との因縁内容がネガティブなら[疲労度]が「対象の因縁強度+1」点減少、ポジティブなら[疲労度]と[改変度]が「対象の因縁強度+1」点ずつ増加する。',
  1130. '死亡。対象は死亡してしまう。対象を【因縁】としていた全てのPCは対象の【因縁】の死亡欄にチェックを入れ、[疲労度]と[改変度]が「対象の因縁強度」点ずつ増加する。',
  1131. '死亡。対象は死亡してしまう。対象を【因縁】としていた全てのPCは対象の【因縁】の死亡欄にチェックを入れ、[疲労度]と[改変度]が「対象の因縁強度」点ずつ増加する。',
  1132. '別人化。対象はあなたとの因縁種別は維持したまま、完全な別人になってしまう。表を振ったプレイヤーは名前表、経歴表を用いて新たな設定を決め直すこと。年齢・性別は変化しない。対象を【因縁】としていた全てのPCは[改変度]が「対象の因縁強度」点ずつ増加する。',
  1133. '因縁種別変化。対象との因縁種別が変わってしまう。表を振ったプレイヤ―は因縁種別表を使用して新たな因縁種別を決定する。その結果、元の因縁種別と違うものになったら、表を振ったプレイヤーのPCは[改変度]が「元の因縁強度」点だけ増加する。',
  1134. '忘却。対象はあなたのことを忘れてしまう。表を振ったプレイヤーのPCはその対象との因縁内容がネガティブなら[疲労度]が「対象の因縁強度」点減少、ポジティブなら[疲労度]が「対象の因縁強度」点増加する。',
  1135. '困窮。対象は経済的に困窮してしまい、その生活は荒れ果ててしまう。その対象との因縁内容がポジティブだった場合、表を振ったプレイヤーのPCは《経済》もしくは《心理》を指定特技として判定を行うことができる。判定に失敗した場合、そのPCは[疲労度]を「対象の因縁強度」点増加させたうえ、ネガティブ因縁内容表を使用して新たに決定し直さなければならない。もともと因縁内容がネガティブだった場合は何も起こらない。',
  1136. '病。対象は不治の病に侵されてしまう。表を振ったプレイヤーのPCは《医療》《漢方》《縁起》のいずれかを指定特技として判定を行うことができる。判定に失敗すると対象は不治の病により死亡してしまう。この表の出目「1or2」の効果を適用すること。',
  1137. '年齢変化。対象の年齢が変わってしまう。表を振ったプレイヤーはまず1D6を振る。奇数なら年齢は減り、偶数なら年齢は増えてしまう。何歳変化するかは1D6を振って決定する。ただし、6の目が出た場合は追加で1D6を振る。6が出るたびにこれを繰り返す。最終的に全ての出目の合計だけ年齢が変化する。変化後の年齢が0才未満になってしまった場合は、対象の存在が消えてしまう。この表の出目「-5or-4」の効果を適用すること。一方、変化後の年齢が「寿命=30+(対象のEL×10)歳」以上になった場合は、寿命を迎えて死亡していないかどうかを決めるため、ランダムに決定した指定特技で判定する。判定に失敗すると対象は死亡してしまう。この表の出目「1or2」の効果を適用すること。また、対象の存在が消えるもしくは死亡しなかった場合でも、結果が矛盾した状態(パラドックス)になったとTAが判断した場合、そのPCの[改変度]が「対象の因縁強度」点増加する。',
  1138. '性別反転。対象の性別が反転してしまう。現在の因縁種別が性別を含むものであれば変更する。例えば次のような形。「実の父親」←→「実の母親」、「実の兄弟」←→「実の姉妹」、「実の祖父」←→「実の祖母」、「養父」←→「養母」、「同性の配偶者」←→「異性の配偶者」など。対象を【因縁】としていた全てのPCのプレイヤーがこの変化を受け入れるのであれば他には何も起こらない。受け入れられないのであれば、そのPCの[疲労度]が「対象の因縁強度」点増加する。また、結果が矛盾した状態(パラドックス)になったとTAが判断した場合、そのPCの[改変度]が「対象の因縁強度」点増加する。',
  1139. '性格反転。対象の性格が反転する。その対象との今の因縁内容がネガティブなら、ポジティブ因縁内容表を使用して決定し直す。今の因縁内容がポジティブなら、ネガティブ因縁内容表を使用して因縁内容を決め直すこと。表を振ったプレイヤーがこの変化を受け入れるのであれば他には何も起こらない。受け入れられないのであれば、そのPCの[疲労度]が「対象の因縁強度」点増加する。',
  1140. '因縁内容変化。対象との因縁内容が変わってしまう。その対象との因縁内容がポジティブだった場合、ポジティブ因縁内容表を、ネガティブだった場合、ネガティブ因縁内容表を使用して因縁内容を決め直すこと。表を振ったプレイヤーがこの変化を受け入れるのであれば他には何も起こらない。受け入れられないのであれば、そのPCの[疲労度]が「対象の因縁強度」点増加する。',
  1141. '宇宙開闢の女神が微笑む。何も変化は起こらなかった。',
  1142. ]
  1143. ),
  1144. 'MBET' => DiceTable::Table.new(
  1145. '軽度バタフライエフェクト表',
  1146. '2D6',
  1147. [
  1148. '激痛。耐え難い激しい痛みが全身を襲う。対象の[疲労度]が「対象の因縁強度」点、[改変度]が「対象の因縁強度+2D6」点増加する。',
  1149. '激痛。耐え難い激しい痛みが全身を襲う。対象の[疲労度]が「対象の因縁強度」点、[改変度]が「対象の因縁強度+2D6」点増加する。',
  1150. '吐血。激しいせき込みの末、吐血してしまう。対象の[疲労度]が「対象の因縁強度」点、[改変度]が「対象の因縁強度+2D6-1」点増加する。',
  1151. '吐血。激しいせき込みの末、吐血してしまう。対象の[疲労度]が「対象の因縁強度」点、[改変度]が「対象の因縁強度+2D6-1」点増加する。',
  1152. '頭痛。頭が割れるような激しい頭痛に襲われる。対象の[疲労度]が「対象の因縁強度の半分」点増加、[改変度]が「対象の因縁強度と同じ値+1D6」点増加する。',
  1153. '頭痛。頭が割れるような激しい頭痛に襲われる。対象の[疲労度]が「対象の因縁強度の半分」点増加、[改変度]が「対象の因縁強度と同じ値+1D6」点増加する。',
  1154. '時間結晶化。身体の一部が時間結晶化する。対象の[改変度]が「対象の因縁強度の半分」点増加する。また、対象がPCだった場合、このセッションの間、好きな【タイムトラベラースキル】を1つだけ追加で修得できる。この【タイムトラベラースキル】はセッション終了時に失われる。',
  1155. '前兆。軽いめまいを感じる。嫌な前兆だ。対象の[疲労度]が1点、対象の[改変度]が「対象の因縁強度の半分」点増加する。',
  1156. '遭遇。自分自身に出会ってしまい時空連続体に亀裂が生じる。何かの事情でこの時代に訪れた別時間軸の自分だろうか。対象の[改変度]が「対象の因縁強度」点増加する。',
  1157. '半透明化。身体がはっきりと半透明になってきた。対象の[改変度]が「対象の因縁強度の半分」点増加する。',
  1158. '外見変化。表を振ったプレイヤーは時代決定表を使用して時代を一つ決定し、その時代の経歴表を使用する。対象はその結果に合った外見・服装に見た目が変化してしまう。対象の[改変度]が「対象の因縁強度の半分」点増加する。',
  1159. '記憶喪失。記憶が混濁し失われていく。対象がPCだった場合、修得している【スキル】のうち、ランダムに選択した【クラススキル】1つがこのセッションの間、使用不能になる。クライマックスフェイズでこのバタフライエフェクトを発生させたPCの【バタフライエフェクト問題】が解決されれば、この効果で使用不能になった【クラススキル】は即座に使用可能になる。対象の[改変度]が「対象の因縁強度の半分」点増加する。',
  1160. '半透明化の兆し。身体が半透明になってきた気がする。対象の[改変度]が1点増加する。',
  1161. '年齢変化。急激に対象の年齢が変化する。表を振ったプレイヤーはまず1D6を振る。奇数なら1D6才若返り、偶数なら1D6才年を取ってしまう。対象の[改変度]が1点増加する。',
  1162. '過去改変。自身の過去が少しだけ書き換わる。対象は新たな経歴を自分の出身時代の経歴表を振って決め直すこと。対象の[改変度]が1点増加する。また、対象がPCだった場合、修得している【クラススキル】を自分のクラスの別の【クラススキル】に変更することができる。',
  1163. '郷愁。ふと意識が宙に浮かび、目の前に故郷の風景が広がる。誰でも郷愁を感じるだろう。対象の[改変度]が1点増加する。',
  1164. '不安。落ち着かない気分になる。対象の[改変度]が1点増加する。',
  1165. '宇宙開闢の女神が微笑む。何も変化は起こらなかった。',
  1166. ]
  1167. ),
  1168. 'TBET' => DiceTable::Table.new(
  1169. 'タイムトラベラー重度バタフライエフェクト表',
  1170. '2D6',
  1171. [
  1172. '消失。PCの存在自体が時空連続体から完全に消失する。PCはロストする。',
  1173. '消失。PCの存在自体が時空連続体から完全に消失する。PCはロストする。',
  1174. '消失の可能性。PCの存在自体があいまいになってしまう。ランダムに選んだ指定特技で判定を行う。判定に失敗すると対象のPCは消失する。PCはロストする。',
  1175. '消失の可能性。PCの存在自体があいまいになってしまう。ランダムに選んだ指定特技で判定を行う。判定に失敗すると対象のPCは消失する。PCはロストする。',
  1176. '時代変更。PCの存在している時代が変わってしまう。時代決定表を振って、新たな出身時代を決定する。違う時代になってしまったら、全ての【因縁】の消失欄にチェックを入れる。また、取得している【クラススキル】を全て失うが、同じ数だけ新たな出身時代の【クラススキル】を取得する。',
  1177. '時代変更。PCの存在している時代が変わってしまう。時代決定表を振って、新たな出身時代を決定する。違う時代になってしまったら、全ての【因縁】の消失欄にチェックを入れる。また、取得している【クラススキル】を全て失うが、同じ数だけ新たな出身時代の【クラススキル】を取得する。',
  1178. '永続時間結晶化。PCの身体の一部が永続的に時間結晶化する。タイムトラベラー特有の能力が強化される。好きな【タイムトラベラースキル】を追加で修得できる。この【スキル】は次回以降のセッションでも修得したままとなる。',
  1179. '死亡。PCは死亡してしまう。PCはロストする。',
  1180. '忘却。PCは記憶を失う。全ての【因縁】の消失欄にチェックを入れる。',
  1181. '改変体質。宇宙開闢の加護の効果が薄まり、PCは歴史改変を受けやすい性質を得てしまう。今後、PCの[改変度]が増加する値が常にプラス1されてしまう。タイムトラベラースキル【時間盾】などによる[改変度]増加量を減少させる効果の前に適用される。',
  1182. 'コミュニケーション障害。宇宙開闢の加護の効果が薄まり、PCはタイムトラベル先の言語を理解しにくくなってしまう。今後、PCが行う接近判定に常にマイナス1の修正が付いてしまう。',
  1183. '病。PCは病に侵されてしまう。病が治るまで(次回から3セッションの間)、セッション開始時の[疲労度]が3になり、セッション中も3より小さい値にならない。',
  1184. '年齢変化。急激にPCの年齢が変化する。まず1D6を振る。奇数なら1D6才若返り、偶数なら1D6才年を取ってしまう。',
  1185. '経歴変化。PCの経歴が変化してしまう。自分の時代の経歴表を振って、新しい経歴を決め直すこと。',
  1186. '性別反転。PCの性別が反転してしまう。',
  1187. '語尾変化。PCは時代特有の語尾が口をついて出てしまうようになる。語尾はセッションの舞台となった時代ごとに下記の通り。原始時代:「ウホ」、古代:「であ~る」、中世時代:「ゴザル」、現代:「じゃん」、超情報化時代:「ゼ」、宇宙時代:「ペモ」。',
  1188. '時代侵食。PCの過去に別の時代が少しだけ侵食する。修得している【クラススキル】1つを自分のクラスとは別のクラスの【クラススキル】に変更することができる。',
  1189. '宇宙開闢の女神が微笑む。何も変化は起こらなかった。',
  1190. ]
  1191. ),
  1192. }.freeze
  1193. 1 register_prefix(RTT.prefixes, TABLES.keys, TABLES_MOD_2D.keys, TABLES_MOD_1D.keys, TABLES_MOD_MINUS.keys)
  1194. end
  1195. end
  1196. end

lib/bcdice/game_system/Pathfinder.rb

100.0% lines covered

100.0% branches covered

8 relevant lines. 8 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/DungeonsAndDragons'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Pathfinder < DungeonsAndDragons
  6. # ゲームシステムの識別子
  7. 1 ID = 'Pathfinder'
  8. # ゲームシステム名
  9. 1 NAME = 'Pathfinder'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'はすふあいんたあ'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = "※このダイスボットは部屋のシステム名表示用となります。\n"
  14. end
  15. end
  16. end

lib/bcdice/game_system/Peekaboo.rb

100.0% lines covered

83.33% branches covered

23 relevant lines. 23 lines covered and 0 lines missed.
6 total branches, 5 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Peekaboo < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Peekaboo'
  7. # ゲームシステム名
  8. 1 NAME = 'ピーカーブー'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ひいかあふう'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定
  14.  判定時にクリティカルとファンブルを自動判定します。
  15. ・各種表
  16.  ・学校イベント表        SET
  17.  ・個別学校イベント表      PSET
  18.  ・オバケ屋敷イベント表     OET
  19.  ・イノセント用バタンキュー!表 IBT
  20.  ・スプーキー用バタンキュー!表 SBT
  21.  ・日中ブラブラ表        NET
  22.  ・オバケぶらり旅表       STT
  23.  ・仲間効果表          NST
  24.  ・ランダム特技決定表      RTT
  25.  ・ランダム分野決定表      RCT
  26.  ・指定特技(不良)表       RTT1, TNT
  27.  ・指定特技(運動)表       RTT2, TET
  28.  ・指定特技(友達)表       RTT3, TFT
  29.  ・指定特技(遊び)表       RTT4, TPT
  30.  ・指定特技(勉強)表       RTT5, TST
  31.  ・指定特技(大人)表       RTT6, TAT
  32. ・D66ダイスあり
  33. INFO_MESSAGE_TEXT
  34. 1 def initialize(command)
  35. 80 super(command)
  36. 80 @sort_add_dice = true
  37. 80 @d66_sort_type = D66SortType::ASC
  38. 80 @round_type = RoundType::CEIL # 端数切り上げに設定
  39. end
  40. # ゲーム別成功度判定(2D6)
  41. 1 def result_2d6(_total, dice_total, _dice_list, cmp_op, _target)
  42. 3 else: 3 then: 0 return nil unless cmp_op == :>=
  43. 3 then: 1 if dice_total <= 2
  44. 1 else: 2 Result.fumble("ファンブル(【眠気】が1d6点上昇)")
  45. 2 then: 1 else: 1 elsif dice_total >= 12
  46. 1 Result.critical("スペシャル(【魔力】あるいは【眠気】が1d6点回復)")
  47. end
  48. end
  49. 1 def eval_game_system_specific_command(command)
  50. 77 roll_tables(command, TABLES) || RTT.roll_command(randomizer, command)
  51. end
  52. 1 RTT = DiceTable::SaiFicSkillTable.new(
  53. [
  54. ['不良', ['夜更かし', 'いねむり', '無視', 'ウソつき', '悪口', 'いたずら', 'ズル', '隠れる', 'ぬすむ', 'おどす', 'けんか',]],
  55. ['運動', ['泳ぐ', '木登り', '柔らかい', 'マラソン', 'とぶ', 'かけっこ', 'バランス', '投げる', '球技', '打ち返す', '力持ち',]],
  56. ['友達', ['ネット', 'うわさ話', '優しさ', 'がまん', 'お手紙', 'おしゃべり', '自転車', '勇気', '約束', '仕切る', '秘密基地',]],
  57. ['遊び', ['パソコン', 'ゲーム', '集める', '絵', '音楽', '空想', '読書', 'お話づくり', 'クイズ', '手品', '占い',]],
  58. ['勉強', ['実験', '宇宙', '生き物', '工作', '計算', '宿題', '漢字', '作文', '歴史', '地理', '外国語',]],
  59. ['大人', ['法律', 'しかる', '手当て', 'マナー', '推理', '計画性', 'お料理', 'お買い物', 'オシャレ', '恋愛', '道楽',]],
  60. ],
  61. rttn: ['TNT', 'TET', 'TFT', 'TPT', 'TST', 'TAT'],
  62. rtt_format: "ランダム指定特技表(%<category_dice>d,%<row_dice>d) > %<text>s",
  63. rttn_format: "指定特技(%<category_name>s)表(%<row_dice>d) > %<text>s"
  64. )
  65. TABLES = {
  66. 1 "SET" => DiceTable::Table.new(
  67. "学校イベント表",
  68. "2D6",
  69. [
  70. "持ち物検査が行われる!イノセント全員は、《隠れる/不良9》の判定を行うこと。失敗したキャラクターは、GMがアイテム1個を選んで没収することができる(セッション終了時に返してもらえる)",
  71. "クラスで流行っている遊びに誘われる。GMは、「遊び」の分野の中からランダムに特技一つを選ぶ。イノセント全員は、その判定を行う。失敗したキャラクターは、【眠気】が1d6点増える。",
  72. "とても退屈な授業が始まった。イノセント全員は、《いねむり/不良3》の判定を行う。失敗したキャラクターは、【眠気】が1d6+1点増える。",
  73. "明日までの宿題を出される。イノセント全員は、明日までに宿題を終わらせないといけない。宿題を終わらせるためには、各サイクルの終わりに、《宿題/勉強7》の判定を行い、それに成功しなければいけない。宿題を次の日の学校フェイズまでに終わらせることができなかった場合は、居残り勉強させられる。その日の放課後フェイズの最初のサイクルは、1回休み。",
  74. "今日も今日とて楽しい授業。GMは、「勉強」の分野の中からランダムに特技1つを選ぶ。イノセント全員は、その判定を行う。失敗したキャラクターは【眠気】が1d6点増える。",
  75. "特に変わったこともなく、おだやかな一日だった。イノセント全員は、【眠気】が1点増える。",
  76. "今日の体育の時間はハードだった! GMは、「運動」の分野の中からランダムに特技1つを選ぶ。イノセント全員は、その判定を行う。失敗したキャラクターは、【眠気】が1d6点増える。",
  77. "自習の時間だ!GMは、「勉強」の分野の中からランダムに特技1つを選ぶ。イノセント全員は、その判定を行う。成功したキャラクターは、1回だけ自由行動ができる。",
  78. "抜き打ちテストだ!GMは、「勉強」の分野の中からランダムに特技1つを選ぶ。イノセント全員は、-2の修正をつけて、その特技の判定を行う。成功したキャラクターはよい点をゲット!家にかえってそれを親に見せるとおこづかいを1個もらえる。失敗したキャラクターは、親にこっぴどく怒られ、【眠気】が1d6点増えるうえに、それ以降「みんなで遊ぶ」ことが出来なくなる。",
  79. "体操服や水着、宿題に提出物などなど、今日は学校に持ってこないといけないものがあったはず!《計画性/大人7》で判定を行う。失敗すると、先生に怒られてしょんぼり。【眠気】が1d6点増える。",
  80. "それぞれに色々なことがあった。イノセントは、各自1回ずつ2d6を振り、個別学校イベント表の指示に従うこと。"
  81. ]
  82. ),
  83. "PSET" => DiceTable::Table.new(
  84. "個別学校イベント表",
  85. "2D6",
  86. [
  87. "クラスの中に気になるコが現れる。《恋愛/大人11》の判定を行う。成功すると、その子と仲良くなって経験値を1点獲得する。",
  88. "お腹の調子が悪くなり、トイレに行きたくなる。《がまん/友達5》か《隠れる/不良9》の判定を行うこと。失敗すると、不名誉なあだ名をつけられ、それ以降、「友達」の分野の判定に-1の修正を受ける。",
  89. "今日の給食には、どうしても苦手な食べ物が出てきた。《勇気/友達9》で判定を行うこと。成功すると、苦手な食べ物を克服し、気分爽快!【眠気】を1d6点回復するか、【元気】を1点回復することができる。",
  90. "友達から遊ぼうと誘われる。その日の放課後フェイズに、クラスメイト1d6人と「みんなで遊ぶ」ことができる。これを断る場合は、《優しさ/友達4》で判定を行うこと。失敗するとこれ以降、「みんなで遊ぶ」を行うとき、友達を誘うことが出来なくなる。",
  91. "今日はクラブ活動があった。次のサイクルは行動できなくなる。その代わり、好きな特技1つを選ぶ。このセッションの間、その特技の判定を行うとき+1の修正がつく。",
  92. "授業中、先生がとても難しい問題を出してくる。GMは、「勉強」の分野からランダムに特技を1つ選ぶ。その判定を行うこと。成功すると、経験値を1点獲得する。",
  93. "クラスでオバケの噂を耳にする。《うわさ話/友達3》の判定に成功すると、GMからそのセッションで出てくるオバケの外見や情報を教えてもらうことができる。",
  94. "校庭や体育館など、自分達の遊び場が他のグループに占拠されている。《けんか/不良12》で判定を行うこと。成功すると、それ以降「友達」の分野の判定に+1の修正を受ける。失敗すると遊び場を失ってしまう。1ダメージを受け、それ以降、「友達と遊ぶ」ことができなくなってしまう。",
  95. "いじめの現場に出くわす! 《勇気/友達10》の判定に成功すると、いじめっこを撃退することができる。いじめられていた子が、お礼にお菓子を1個くれる。失敗すると1点のダメージを受ける。",
  96. "今日は全校集会があった。《がまん/友達5》で判定を行う。失敗すると貧血で倒れ次のサイクルは行動できなくなる。",
  97. "図書室で面白そうな本を発見する。《読書/遊び8》で判定を行うこと。成功すると、経験値を1点獲得する。"
  98. ]
  99. ),
  100. "OET" => DiceTable::Table.new(
  101. "お化け屋敷イベント表",
  102. "2D6",
  103. [
  104. "謎かけ守護者が門を護っている。未行動のキャラクターは、《クイズ/遊び10》の判定を行うことができる。判定したキャラクターは行動済みになる。失敗したキャラクターは、1点のダメージを受ける。誰かが成功すれば、イベントはクリアできる。",
  105. "天井から血の雨が降ってくる! この雨に触れると火傷しちゃうみたいだ!【防御力】が0のスプーキーとイノセントは、《かけっこ/運動7》の判定を行う。失敗すると、イノセントは1ダメージ、スプーキーは1d6ダメージを受ける。成功・失敗にかかわらず、イベントはクリアできる。",
  106. "トンガリ族の妖精がいる。彼は、先へ行くための通行料として、アイテムを要求してくる。何か好きなアイテム1個を渡すか、未行動のキャラクターは、《お話づくり/遊び9》の判定を行うことができる。判定したキャラクターは行動済みになる。誰かが判定に成功するか、アイテムを渡すかしたら、イベントはクリアできる。",
  107. "行き止まりだ。先に進む方法が分からない。未行動のキャラクターは、《推理/大人6》の判定を行うことができる。判定したキャラクターは行動済みになる。誰かが成功したら、イベントはクリアできる。",
  108. "まっくらで、何も見えない部屋だ。一行は不安におちいる。未行動のキャラクターは、《仕切る/友達11》の判定を行うことができる。判定したキャラクターは行動済みになる。誰かが成功すれば、イベントはクリアできる。",
  109. "ジメジメした通路だ。特に何もしなくても、イベントはクリアだ。誰かがのぞむなら、自由行動を1回行うことができるぞ。",
  110. "通路が途中で途切れて崖のようになっている。誰かが飛ぶことが出来れば、向こう岸にあるはしごを断崖にかけられそうだけど……。未行動のキャラクターは、《とぶ/運動6》の判定を行うことができる。判定したキャラクターは行動済みになる。誰かが成功すれば、イベントはクリアできる。",
  111. "まぼろしの部屋だ。各キャラクターの大好物のまぼろしがつぎつぎ現れる。未行動のキャラクターは、《がまん/友達5》の判定を行うことができる。判定したキャラクターは行動済みになる。誰かが成功したら、イベントはクリアできる。",
  112. "通路がいくつにも分岐している……。未行動のキャラクターのうち1人が《地理/勉強11》、もしくは《絵/遊び5》の判定を行う。判定したキャラクターは行動済みになる。失敗すると、そのオバケ屋敷の部屋数が1d6点上昇する。成功失敗にかかわらず、イベントはクリアできる。",
  113. "シャドウが見回りをしている。未行動のキャラクターのうち1人が、《隠れる/不良9》の判定を行う。成功すれば、イベントはクリアできる。失敗すると、プレイヤーと同じ人数のシャドウと戦闘を行うこと。勝利すればイベントはクリアできる。",
  114. "足下からシャドウが現れ、みんなに襲いかかる!プレイヤーと同じ人数のシャドウと戦闘を行うこと。勝利すればイベントはクリアできる。"
  115. ]
  116. ),
  117. "NET" => DiceTable::Table.new(
  118. "日中ブラブラ表",
  119. "2D6",
  120. [
  121. "相棒のスプーキーと喧嘩する。1d6サイクルの間、自分の相棒のスプーキーは、自分に対して【お助け力】を使用することができなくなる。",
  122. "ついついネットやゲームで時間をつぶす。特に何もなし。。",
  123. "街をブラブラしていたら、突然シッポ族のオバケに襲われる。「お前、大人のくせに俺が見えるのか?」GMは「運動」の分野の中から、ランダムに特技を1つ選ぶ。この表の使用者は、その判定を行う。成功したら、オバケに気に入られ、セッション中、好きな時に一度だけ、シッポ族の魔法をかけてもらうことができるようになる。失敗すると1点のダメージを受ける。",
  124. "…暇だ。たまには、タメになりそうな本でも読んでみるか。GMは「勉強」の分野の中から、ランダムに特技1つを選ぶ。この表の使用者はその判定を行う。成功したら、セッション中、好きな時に一度だけ、判定を自動的に成功することができるようになる。失敗すると退屈のあまり【眠気】が1d6点上昇する。",
  125. "ああ、まずい。会いたくないヤツに会っちまったなぁ。どうやって誤魔化そう?GMは「不良」の分野の中から、ランダムに特技1つを選ぶ。この表の使用者は、その判定を行う。成功したら、うまく誤魔化してそのシナリオに登場するハグレオバケの噂を手に入れることができる。失敗するとお説教をくらって【眠気】が1d6点上昇する。",
  126. "ふわわわわ。眠いなぁ。……寝るか。【眠気】を2d6点回復する。",
  127. "うーん。腹減った。何か食べたいけど……。GMは「大人」の分野の中から、ランダムに特技を1つ選ぶ。この表の使用者はその判定を行う。成功したら、【お菓子】を1d6個手に入れる。失敗すると、持っていれば【おこづかい】を一個減らす。",
  128. "うーん。そうだ。あいつに連絡してみるか……。GMは「友達」分野の中からランダムに特技1つを選ぶ。この表の使用者は、その判定を行う。成功したら友達の力を借りて、それ以降の自分の手番に二回行動することができるようになる。失敗すると、誰にも捕まらず、寂しさのあまり【眠気】が1d6点上昇する。",
  129. "臨時のバイト。久々の労働だ。GMは「遊び」の分野の中から、ランダムに特技を1つ選ぶ。この表の使用者は、その判定を行う。成功したら、【おこづかい】を1つ獲得できる。失敗すると【眠気】が1d6点上昇する。",
  130. "あ、これ欲しかったんだよな。つい無駄な買い物をしてしまう。持っていれば【おこづかい】を一個減らす。",
  131. "相棒のスプーキーと、素敵な時間を過ごす。そのセッションの間だけ、「武装契約」「守護契約」「強化契約」「同調契約」のいずれか一つを結ぶことができる。"
  132. ]
  133. ),
  134. "IBT" => DiceTable::Table.new(
  135. "イノセント用バタンキュー!表",
  136. "1D6",
  137. [
  138. "悲しい別れ。病院につれていくことができれば、1d6日入院したあとに目覚めます。その間は、行動不能です。目覚めたときに【眠気】も【元気】もすべて回復しますが、スプーキーを見ることができなくなっています。そのキャラクターはスプーキーと一緒に冒険を続けることはできません……。",
  139. "大けがをして昏睡状態。病院につれていくことができれば、1d6日入院したあとに目覚めます。その間は、行動不能です。目覚めたときに【眠気】はすべて回復し、【元気】が3点回復します。",
  140. "気絶しちゃった! 1d6サイクル後に目覚めます。気絶している間は、行動不能です。目覚めたときに【眠気】が1d6点、【元気】が1点回復します。",
  141. "体が動かない! 何かを見たり、話したりといった簡単な行動ならできますが、自由行動や戦闘行動といった通常の行動は行えません。1d6サイクル後に【元気】が1点回復し、通常通り行動できるようになります。",
  142. "かろうじて意識はあるものの、朦朧としてきた。【眠気】が2d6点増えます。それで行動不能になっていなければ、【元気】が1点回復します。そうでなければ、気絶してしまい、1d6サイクル後に目覚めます。気絶している間は、行動不能です。目覚めたときに【眠気】が1d6点減少し、【元気】が1点回復します。",
  143. "なんという幸運!アイテムがキミを護ってくれた。もし持ち物にアイテムがあった場合、それが1個破壊され、受けたダメージを無効化します。アイテムがなければ行動不能になります。"
  144. ]
  145. ),
  146. "SBT" => DiceTable::Table.new(
  147. "スプーキー用バタンキュー!表",
  148. "1D6",
  149. [
  150. "封印状態! オバケは封印されてしまいます。1d6*1年後になれば、そのオバケは復活します。それまでは、イノセントと一緒に冒険することはできません。できたとしても、そのときイノセントはあなたを見ることができなくなっているかもしれませんが……。",
  151. "休眠状態! オバケは休眠状態になります。1d6日が経過すると目覚めます。その間は、行動不能です。目覚めたときに【魔力】はすべて回復しています。",
  152. "コバケ状態! 体は小さく縮んてしまい、重戦闘も戦闘行動も行うことはできません。【魔力】が1点以上になると、通常通り行動できるようになります。",
  153. "混沌変化! 自分のリングのからだリストを使って、ランダムにからだを1つ選びます。自分のからだが、それに変化します。1d6サイクルの間、行動不能になります。その後、【魔力】が1d6点回復して通常通り行動できるようになります。",
  154. "魔力変質! 自分のリングの衣装リストを使って、ランダムに衣装を1つ選びます。自分の衣装1つが、それに変化します。そして、1d6サイクルの間、行動不能になります。その後、【魔力】が1d6点回復して通常通り行動できるようになります。",
  155. "魔法暴発! 自分の持っている魔法をランダムに1つ選んで、その効果が発動します。魔法の対象が選べる場合は、スプーキーのプレイヤーが選んで構いません。そして、1d6サイクルの間、行動不能になります。その後、【魔力】が1d6点回復して通常通り行動できるようになります。"
  156. ]
  157. ),
  158. "STT" => DiceTable::Table.new(
  159. "オバケぶらり旅表",
  160. "2D6",
  161. [
  162. "オバケ狩りに遭遇してしまいますオバケ判定を行ってください。失敗すると2d6点のダメージを受けます。",
  163. "リングの上司からレポートを提出しろといわれます。セッション終了に、今回の冒険がどんな話だったかをまとめ、GMに報告してください。GMが、その報告がうまくまとまっていると感じたら、そのスプーキーとイノセントのコンビがもらえる経験点が1点上昇します。",
  164. "近所のお家に忍び込み、めぼしいものを探しました。オバケ判定を行ってください。成功すると、ルールブック228頁に書いてあるアイテム表を使ってランダムで決めたアイテム1個を入手します。",
  165. "街の優しいおばけたちに頼まれます。そのシナリオに登場するはぐれオバケを説得し、悪事をやめさせることができれば、そのスプーキーとイノセントのコンビがもらえる経験点が1点上昇します。",
  166. "オバケたちとギャンブルに興じます♪好きなだけ【魔力】を減少してください。サイコロを1個振ります。奇数が出たらギャンブルに勝利!減少した【魔力】の2倍の値だけ魔力が回復します。偶数が出たらギャンブルに敗北(しょぼん)。減少した魔力はかえってきません。",
  167. "オバケたちのウワサを耳にします。GMは、シナリオ上で重要な情報を1つ選んで下さい。その情報を入手することができます。",
  168. "人間について学習します。オバケ判定を行って下さい。成功すると、ランダムに好きな特技を1つ選びます。そのゲームの間、その特技を習得しているものとして、行為判定を行うことができるようになります。",
  169. "リングのオバケ学校で再修行。自分の魔法1つを未取得にします。そして、共用か自分のリングの魔法リストから、ランダムに魔法を1つ選び、新たに修得します。",
  170. "突如、誰かの役に立ちたいと思いました。このセッションが終わるまでに、そのスプーキーとイノセントのコンビに対して、5人以上のキャラクターが「ありがとう」と言ったら、コンビのもらえる経験点が1点上昇します。",
  171. "道端で拾ったものがオバケ市場で売れました。ラッキー♪お小遣いを1つ入手できます。",
  172. "オバケ狩りから身を隠すために変装します。自分の衣装1つを未取得にします。そして、共用か自分のリングの衣装から、ランダムに衣装を1つ選び、新たに修得します。"
  173. ]
  174. ),
  175. "SAT" => DiceTable::Table.new(
  176. "オバケ行動表",
  177. "2D6",
  178. [
  179. "「えー。お前なんか嫌いだ!」スプーキーは、イノセントとけんかしてしまいます。そのサイクルは行動せず、【魔力】も回復しません。",
  180. "「疲れたよーん」スプーキーは、行動をパスして【魔力】を回復します。",
  181. "「ムムム。気になる、気になるぞー」スプーキーは、戦闘フェイズなら「ひみつを暴く」を行います。それ以外なら「オバケ占い」を行います。",
  182. "「やっぱ定番はこうでしょう」スプーキーは、戦闘フェイズなら「攻撃」を行います。それ以外なら「調査」を行います。",
  183. "「オバケ的にはどう思う?」スプーキーは、ほかのスプーキーのいうことをききます。",
  184. "「うん、そうするー」スプーキーは自分の契約しているイノセントのいうことをききます。",
  185. "「うーん。そうかなぁ?」スプーキーは、ほかのイノセントのいうことをききます。",
  186. "「トリック・オア・トリート!」スプーキーは、何かのアイテム(お菓子やおこづかいが適当でしょう)をもらえたら、イノセントのいうことをききます。もらったアイテムは、即座に消費されます。",
  187. "「ここは派手にいきたいぜ!」スプーキーは、自分の修得している魔法をランダムに1個選んで、それを使用します。対象を決める場合は、自由に選んで構いません。",
  188. "「ここは様子見だなぁ」スプーキーは、行動をパスして【魔力】を回復します。",
  189. "「こうなりゃ本気モードだ!」スプーキーは自分の契約しているイノセントのいうことをききます。また、そのサイクルの間、そのスプーキーは魔力の消費なしで、魔法を使用することができます。"
  190. ]
  191. ),
  192. "NST" => DiceTable::Table.new(
  193. "仲間効果表",
  194. "1D6",
  195. [
  196. "用心棒。この仲間の効果は、誰かがダメージを受けた時に使用できる。そのダメージを無効化する。",
  197. "パトロン。この仲間の効果は、好きな時に使用できる。【おこづかい】一つか、ランダムに選んだアイテム一つを獲得できる。",
  198. "助言。この仲間の効果は、誰かが判定を行うときに使用できる。そのNPCが人間の場合、その判定に使う特技が、そのNPCが修得している特技なら、自動的に成功になる。そのNPCがオバケの場合、その判定にプラス2かマイナス2の修正をつけることができる。",
  199. "師匠。この仲間の効果は、好きな時に使用できる。そのNPCが人間の場合、ランダムに選んだ才能を一つ獲得する。この効果は、その日の終りまで持続する。そのNPCがオバケの場合、そのオバケが修得している好きな魔法を一つ使用する。",
  200. "時間稼ぎ。好きな行動済みのキャラクター1人を未行動にしてくれる。",
  201. "乱入行動。自分が攻撃に成功した時に使用できる。そのダメージを1d6点上昇してくれる。"
  202. ]
  203. ),
  204. }.freeze
  205. 1 register_prefix(RTT.prefixes, TABLES.keys)
  206. end
  207. end
  208. end

lib/bcdice/game_system/Pendragon.rb

100.0% lines covered

90.0% branches covered

17 relevant lines. 17 lines covered and 0 lines missed.
10 total branches, 9 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Pendragon < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Pendragon'
  7. # ゲームシステム名
  8. 1 NAME = 'ペンドラゴン'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'へんとらこん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. クリティカル、成功、失敗、ファンブルの自動判定を行います。
  14. INFO_MESSAGE_TEXT
  15. # ゲーム別成功度判定(1d20)
  16. 1 def result_1d20(total, _dice_total, cmp_op, target)
  17. 8 then: 1 else: 7 return Result.nothing if target == '?'
  18. 7 else: 7 then: 0 return nil unless cmp_op == :<=
  19. 7 then: 4 if total <= target
  20. 4 then: 2 if (total >= (40 - target)) || (total == target)
  21. 2 Result.critical("クリティカル")
  22. else: 2 else
  23. 2 Result.success("成功")
  24. else: 3 end
  25. 3 then: 1 elsif total == 20
  26. 1 Result.fumble("ファンブル")
  27. else: 2 else
  28. 2 Result.failure("失敗")
  29. end
  30. end
  31. end
  32. end
  33. end

lib/bcdice/game_system/PersonaO.rb

97.3% lines covered

90.0% branches covered

37 relevant lines. 36 lines covered and 1 lines missed.
10 total branches, 9 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class PersonaO < Base
  5. # ゲームシステムのの識別子
  6. 1 ID = 'PersonaO'
  7. # ゲームシステム名
  8. 1 NAME = 'ペルソナTRPG-O'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'へるそなTRPGO'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・基本判定
  14.  PTx@y x:目標値、y:クリティカル値(省略時は5)
  15.  例)PT60 PT90@10
  16. ・ダメージ計算
  17.  nPD+(x+y*2)%(z-a)-b n:ダイス個数、x:スキル固定値、y:ボーナス、z:バフ倍率、a:耐性、b:敵防御力
  18.  nPD+(x+y*2)までがスキルによる素のダメージ、zおよびaは計算式を入れてよい。
  19.  
  20.  例)ソニックパンチ、力B2点、
  21.    タルカジャがかかっており、打撃耐性あり、
  22.    目標の物理防御力は2点
  23.    
  24.    2PD+(20+2*2)%(100+50-50)-2
  25. INFO_MESSAGE_TEXT
  26. 1 register_prefix(
  27. 'PT',
  28. '\d+PD'
  29. )
  30. 1 def eval_game_system_specific_command(command)
  31. 13 roll_attack(command) || roll_damage(command)
  32. end
  33. 1 private
  34. 1 def roll_attack(command)
  35. 13 m = /^PT(-?\d+)?(@(-?\d+))?$/i.match(command)
  36. 13 else: 11 then: 2 unless m
  37. 2 return nil
  38. end
  39. 11 success_rate = m[1].to_i
  40. 11 then: 4 else: 7 critical_border = m[3]&.to_i || 5
  41. 11 dice_value = @randomizer.roll_once(100)
  42. result =
  43. 11 then: 2 if dice_value <= critical_border
  44. 2 else: 9 Result.critical("クリティカル")
  45. 9 then: 7 elsif dice_value <= success_rate
  46. 7 Result.success("成功")
  47. else: 2 else
  48. 2 Result.failure("失敗")
  49. end
  50. 11 result.text = "D100<=#{success_rate}@#{critical_border} > #{dice_value} > #{result.text}"
  51. 11 return result
  52. end
  53. 1 def roll_damage(command)
  54. 2 m = /^(\d+)PD\+(-?\d+)%(-?\d+)-(\d+)$/i.match(command)
  55. 2 else: 2 then: 0 unless m
  56. return nil
  57. end
  58. 2 dice = m[1].to_i
  59. 2 kotei = m[2].to_i
  60. 2 hosei = m[3].to_i
  61. 2 bougyo = m[4].to_i
  62. 2 dice_list = @randomizer.roll_barabara(dice, 10)
  63. 2 dice_sum = dice_list.sum
  64. 2 dmg = dice_sum + (hosei * kotei / 100.0).to_i - bougyo
  65. 2 return "#{dice}D10+#{kotei}*#{hosei}%-#{bougyo} > [#{dice_list.join(',')}]+#{kotei}*#{hosei}%-#{bougyo} > #{dmg} ダメージ!"
  66. end
  67. end
  68. end
  69. end

lib/bcdice/game_system/PhantasmAdventure.rb

76.32% lines covered

50.0% branches covered

38 relevant lines. 29 lines covered and 9 lines missed.
28 total branches, 14 branches covered and 14 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class PhantasmAdventure < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'PhantasmAdventure'
  7. # ゲームシステム名
  8. 1 NAME = 'ファンタズム・アドベンチャー'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ふあんたすむあとへんちやあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. 成功、失敗、決定的成功、決定的失敗の表示とクリティカル・ファンブル値計算の実装。
  14. INFO_MESSAGE_TEXT
  15. # ゲーム別成功度判定(1d20)
  16. 1 def result_1d20(total, _dice_total, cmp_op, diff)
  17. 31 then: 1 else: 30 return Result.nothing if diff == '?'
  18. 30 else: 30 then: 0 return nil unless cmp_op == :<=
  19. # 技能値の修正を計算する
  20. 30 skill_mod = 0
  21. 30 then: 0 if diff < 1
  22. else: 30 skill_mod = diff - 1
  23. 30 then: 0 else: 30 elsif diff > 20
  24. skill_mod = diff - 20
  25. end
  26. 30 fumble = 20 + skill_mod
  27. 30 then: 0 else: 30 fumble = 20 if fumble > 20
  28. 30 critical = 1 + skill_mod
  29. 30 dice_now = @randomizer.roll_once(20)
  30. 30 then: 1 if (total >= fumble) || (total >= 20)
  31. 1 fum_num = dice_now - skill_mod
  32. 1 then: 0 else: 1 fum_num = 20 if fum_num > 20
  33. 1 then: 0 else: 1 fum_num = 1 if fum_num < 1
  34. 1 fum_str = dice_now.to_s
  35. 1 then: 0 if skill_mod < 0
  36. fum_str += "+#{skill_mod * -1}=#{fum_num}"
  37. else: 1 else
  38. 1 fum_str += "-#{skill_mod}=#{fum_num}"
  39. end
  40. 1 return Result.fumble("致命的失敗(#{fum_str})")
  41. else: 29
  42. 29 then: 0 elsif (total <= critical) || (total <= 1)
  43. crit_num = dice_now + skill_mod
  44. then: 0 else: 0 crit_num = 20 if crit_num > 20
  45. then: 0 else: 0 crit_num = 1 if crit_num < 1
  46. then: 0 else: 0 if skill_mod < 0
  47. return Result.success("成功")
  48. end
  49. else: 29 return Result.critical("決定的成功(#{dice_now}+#{skill_mod}=#{crit_num})")
  50. 29 then: 14 elsif total <= diff
  51. 14 return Result.success("成功")
  52. else: 15 else
  53. 15 return Result.failure("失敗")
  54. end
  55. end
  56. end
  57. end
  58. end

lib/bcdice/game_system/Postman.rb

100.0% lines covered

90.63% branches covered

80 relevant lines. 80 lines covered and 0 lines missed.
32 total branches, 29 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Postman < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Postman'
  7. # ゲームシステム名
  8. 1 NAME = '壊れた世界のポストマン'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'こわれたせかいのほすとまん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ◆判定:[n]PO[+-a][> or >= or @X]  []内省略可。
  14. 達成値と判定の成否、クリティカル、ファンブルを結果表示します。
  15. 「n」でダイス数を指定。省略時は2D。
  16. 「+-a」で達成値への修正を指定。「+2+1-4」のような複数回指定可。
  17. 「>X」「>=X」「@X」で難易度を指定可。
  18. 「>X」は達成値>難易度、「>=X」「@X」は達成値>=難易度で判定します。
  19. 【書式例】
  20. 3PO+2-1 → 3Dで達成値修正+1の判定。達成値のみ表示。
  21. PO@5+2 → 2Dで目標値7の判定。判定の成否と達成値を表示。
  22. 4PO-2+1>7+2 → 4Dで達成値修正-1、目標値9(同値は失敗)の判定。
  23. ◆天候チェック:WEA[n]  []内省略可。
  24. 天候チェック表を参照します。
  25. 「n」を指定すると、指定した結果を表示します。(【幸運点】使用時用)
  26. ◆自由行動シチュエーション表:FRE
  27. MESSAGETEXT
  28. 1 register_prefix(
  29. 'WEA',
  30. '(\d+)?PO',
  31. 'FRE'
  32. )
  33. 1 def initialize(command)
  34. 31 super(command)
  35. 31 @sort_add_dice = true # ダイスのソート有
  36. end
  37. 1 def eval_game_system_specific_command(command)
  38. text =
  39. 31 else: 0 case command.upcase
  40. when: 26 when /(\d+)?PO(\d+)?(([+-]\d+)*)?((>|>=|@)(\d+)(([+-]\d+)*)?)?/i
  41. 26 diceCount = (Regexp.last_match(1) || 2).to_i
  42. 26 then: 1 else: 25 diceCount = 2 if diceCount < 2
  43. 26 modify = (Regexp.last_match(2) || 0).to_i
  44. 26 modifyAddString = Regexp.last_match(3) || ''
  45. 26 type = Regexp.last_match(6) || ''
  46. 26 target = (Regexp.last_match(7) || 0).to_i
  47. 26 targetAddString = Regexp.last_match(8) || ''
  48. 26 modify_list = modifyAddString.scan(/[+-]\d+/)
  49. 35 modify_list.each { |i| modify += i.to_i }
  50. 26 then: 13 else: 13 if target != 0
  51. 13 target_list = targetAddString.scan(/[+-]\d+/)
  52. 16 target_list.each { |j| target += j.to_i }
  53. end
  54. 26 checkRoll(diceCount, modify, type, target)
  55. when: 3 when /WEA(\d+)?/i
  56. 3 roc = (Regexp.last_match(1) || 0).to_i
  57. 3 get_weather_table(roc)
  58. when: 2 when 'FRE'
  59. 2 get_free_situation_table
  60. end
  61. 31 return text
  62. end
  63. 1 def checkRoll(diceCount, modify, type, target)
  64. 26 diceArray = @randomizer.roll_barabara(diceCount, 6).sort
  65. 26 dice = diceArray.sum()
  66. 26 diceText = diceArray.join(",")
  67. 26 dice2 = diceArray[-2] + diceArray[-1]
  68. 26 diceText2 = "#{diceArray[-2]},#{diceArray[-1]}"
  69. 26 criticalCount = diceArray.count(6)
  70. 26 then: 8 else: 18 if modify != 0
  71. 8 modifyText = ''
  72. 8 then: 4 else: 4 modifyText = "+" if modify > 0
  73. 8 modifyText += modify.to_s
  74. end
  75. 26 result = dice2 + modify
  76. 26 then: 13 else: 13 if type != ''
  77. 13 resultText = " 【失敗】"
  78. 13 operatorText = ">"
  79. 13 then: 2 if type == '>'
  80. 2 then: 1 else: 1 resultText = " 【成功】" if result > target
  81. else: 11 else
  82. 11 operatorText += "="
  83. 11 then: 4 else: 7 resultText = " 【成功】" if result >= target
  84. end
  85. end
  86. 26 then: 3 if criticalCount >= 2
  87. 3 else: 23 resultText = " 【成功】(クリティカル)"
  88. 23 then: 3 else: 20 elsif dice == diceCount
  89. 3 resultText = " 【失敗】(ファンブル)"
  90. end
  91. 26 text = "#{diceCount}D6(#{diceText})#{modifyText} > #{dice2}(#{diceText2})#{modifyText} = 達成値:#{result}"
  92. 26 then: 13 else: 13 text += "#{operatorText}#{target} " if target > 0
  93. 26 text += resultText.to_s
  94. 26 return text
  95. end
  96. 1 def get_weather_table(roc)
  97. 3 name = "天候チェック"
  98. table = [
  99. 3 [2, '大雨と強風。探索判定の難易度に+4。'],
  100. [3, '風が強い1日になりそう。探索判定の難易度に+2。'],
  101. [4, '晴れ。特になし。'],
  102. [5, '夜の間の雨でぬかるむ。探索判定の難易度に+2。'],
  103. [6, 'それなりの雨足。探索判定の難易度に+2。'],
  104. [7, '晴れ。特になし。'],
  105. [8, '天気は大荒れ。探索判定の難易度に+4。'],
  106. [9, '小雨が降る。探索判定の難易度に+1。'],
  107. [10, 'それなりの雨足。探索判定の難易度に+2。'],
  108. [11, '晴れ。特になし。'],
  109. [12, '風が強い1日になりそう。探索判定の難易度に+2。']
  110. ]
  111. 3 then: 2 if roc == 0
  112. 2 dice_list = @randomizer.roll_barabara(2, 6)
  113. 2 dice = dice_list.sum()
  114. 2 diceText = dice_list.join(",")
  115. else: 1 else
  116. 1 then: 0 else: 1 roc = 2 if roc < 2
  117. 1 then: 1 else: 0 roc = 12 if roc > 12
  118. 1 dice = roc
  119. 1 diceText = "Choice:#{roc}"
  120. end
  121. 3 tableText = get_table_by_number(dice, table)
  122. 3 text = "#{name}(#{diceText}) > #{dice}:#{tableText}"
  123. 3 return text
  124. end
  125. 1 def get_free_situation_table()
  126. 2 name = "自由行動シチュエーション表"
  127. table = [
  128. 2 [2, '何をするでもなく、霞がかったような夜空を見上げる。ふと隣に目を向ければ、彼/彼女が居た。彼/彼女は、こうなる前の夜空を知っているのだろうか。'],
  129. [3, '夢を見た。大戦の最中、街が、人が、世界が焼けていく悪夢を。追い立てられるようにして目を覚ますと、彼/彼女が君を見ていた。 ……もしかして、自分はよほどうなされていたのだろうか。'],
  130. [4, '周囲で見つけたガラクタを使って、ちょっとしたビックリ玩具を作ってみた。「彼/ 彼女」にコイツをけしかけたら、どんな反応をするだろうか?'],
  131. [5, '使えそうなものがないか探していると、カタンと物音がして何かが落ちた。拾い上げてみたそれは、かつてここで生活していた誰かの名残(写真、家具、玩具等)だった。'],
  132. [6, 'テントの中で夜を過ごしていると、ふと彼/彼女と話したくてたまらない気持ちになった。言ってしまえば、夜の静けさに寂しさを覚えてしまったのだ。'],
  133. [7, 'ここまでの配達の記録をつけていたら、背後から視線を感じる……! もしや、彼/彼女に覗かれている……!?'],
  134. [8, '周囲を探索していると、君一人では手の届かないところに金属製の箱か何かがあることに気づいた。彼/彼女に手伝ってもらえば、取れるだろうか……?'],
  135. [9, '朝まではまだしばらくあるというのに、目が覚めてしまった。二度寝しようにも寝付けずに居ると、隣でもぞもぞと動く気配がする。彼/彼女も、どうやら同じらしい。'],
  136. [10, '他愛のない話をするうちに、君は彼/彼女に問いかけていた。「何故、ポストマンになろうと思ったのか」 ……そういえば、君自身はどうだったろうか。'],
  137. [11, '保存食にありつこうとしたその時、君は気づいた。一匹のネズミが、彼/彼女の荷物の中に潜り込もうとしている。彼/彼女は気づいていないが、このままでは食料が危ない!'],
  138. [12, 'テントを設営し、落ち着いた頃にふと気づく。 ……身体が熱い。少し、だるさもあるような気もする。大したことはないと思うが、彼/彼女に相談しておいた方がいいだろうか。']
  139. ]
  140. 2 dice_list = @randomizer.roll_barabara(2, 6)
  141. 2 dice = dice_list.sum()
  142. 2 diceText = dice_list.join(",")
  143. 2 tableText = get_table_by_number(dice, table)
  144. 2 text = "#{name}(#{diceText}) > #{dice}:#{tableText}"
  145. 2 return text
  146. end
  147. end
  148. end
  149. end

lib/bcdice/game_system/PulpCthulhu.rb

97.56% lines covered

90.0% branches covered

41 relevant lines. 40 lines covered and 1 lines missed.
10 total branches, 9 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/Cthulhu7th"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class PulpCthulhu < Cthulhu7th
  6. # ゲームシステムの識別子
  7. 1 ID = 'PulpCthulhu'
  8. # ゲームシステム名
  9. 1 NAME = 'パルプ・クトゥルフ'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'はるふくとうるふ'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ※私家翻訳のため、用語・ルールの詳細については原本を参照願います。
  15. ※コマンドは入力内容の前方一致で検出しています。
  16. ・判定 CC(x)<=(目標値)
  17.  x:ボーナス・ペナルティダイス (2~-2)。省略可。
  18.  目標値が無くても1D100は表示される。
  19.  ファンブル/失敗/
  20.  成功/ハード成功/イクストリーム成功/クリティカル を自動判定。
  21. 例)CC<=30 CC(2)<=50 CC(-1)<=75 CC-1<=50 CC1<=65 CC
  22. ・組み合わせ判定 (CBR(x,y))
  23.  目標値 x と y で%ロールを行い、成否を判定。
  24.  例)CBR(50,20)
  25. ・自動火器の射撃判定 FAR(w,x,y,z,d)
  26.  w:弾丸の数(1~100)、x:技能値(1~100)、y:故障ナンバー、
  27.  z:ボーナス・ペナルティダイス(-2~2)。省略可。
  28.  d:指定難易度で連射を終える(レギュラー:r,ハード:h,イクストリーム:e)。省略可。
  29.  命中数と貫通数、残弾数のみ算出。ダメージ算出はありません。
  30. 例)FAR(25,70,98) FAR(50,80,98,-1) far(30,70,99,1,R)
  31.   far(25,88,96,2,h) FaR(40,77,100,,e)
  32. ・各種表
  33.  【狂気関連】
  34.  ・狂気の発作(リアルタイム)(Bouts of Madness Real Time) BMR
  35.  ・狂気の発作(サマリー)(Bouts of Madness Summary) BMS
  36.  ・恐怖症(Sample Phobias)表 PH/マニア(Sample Manias)表 MA
  37.  ・狂気のタレント(Insane Talents)表 IT
  38.  【魔術関連】
  39.  ・プッシュ時のキャスティング・ロールの失敗(Failed Casting Effects)表 FCE
  40. INFO_MESSAGE_TEXT
  41. 1 register_prefix('CC', 'CBR', 'FAR', 'BMR', 'BMS', 'FCE', 'PH', 'MA', 'IT')
  42. 1 def eval_game_system_specific_command(command)
  43. 22 case command
  44. when: 2 when /^CC/i
  45. 2 return skill_roll(command)
  46. when: 1 when /^CBR/i
  47. 1 return combine_roll(command)
  48. when: 1 when /^FAR/i
  49. 1 return getFullAutoResult(command)
  50. when: 3 when /^BMR/i # 狂気の発作(リアルタイム)
  51. 3 return roll_bmr_table()
  52. when: 3 when /^BMS/i # 狂気の発作(サマリー)
  53. 3 return roll_bms_table()
  54. when: 3 when /^FCE/i # キャスティング・ロールのプッシュに失敗した場合
  55. 3 return roll_1d20_table("キャスティング・ロール失敗表", FAILED_CASTING_EFFECTS_TABLE)
  56. when: 3 when /^PH/i # 恐怖症表
  57. 3 return roll_1d100_table("恐怖症表", PHOBIAS_TABLE)
  58. when: 3 when /^MA/i # マニア表
  59. 3 return roll_1d100_table("マニア表", MANIAS_TABLE)
  60. when: 3 when /^IT/i # 狂気のタレント表
  61. 3 return roll_1d20_table("狂気のタレント表", INSANE_TALENTS_TABLE)
  62. else: 0 else
  63. return nil
  64. end
  65. end
  66. 1 private
  67. 1 def roll_1d20_table(table_name, table)
  68. 6 total_n = @randomizer.roll_once(20)
  69. 6 index = total_n - 1
  70. 6 text = table[index]
  71. 6 return "#{table_name}(#{total_n}) > #{text}"
  72. end
  73. # 表一式
  74. # 即時の恐怖症表
  75. 1 def roll_bmr_table()
  76. 3 total_n = @randomizer.roll_once(10)
  77. 3 text = MADNESS_REAL_TIME_TABLE[total_n - 1]
  78. 3 time_n = @randomizer.roll_once(10)
  79. 3 return "狂気の発作(リアルタイム)(#{total_n}) > #{text}(1D10>#{time_n}ラウンド)"
  80. end
  81. 1 MADNESS_REAL_TIME_TABLE = [
  82. '健忘症:ヒーローは自分自身がヒーローである考えをやめ、1D10ラウンドの間パルプのタレントを失う。',
  83. '狂った計画:1D10ラウンドの間ヒーローは不合理的または非効率的な計画を考えつく。その計画は敵を有利にするものかもしれないし、ヒーローの仲間に対して危険を高めるものかもしれない。',
  84. '怒り:頭に血が上り1D10ラウンドの間、周囲の人間、味方、敵問わず暴力と破壊を振りまく。',
  85. 'おごり高ぶる:1D10ラウンドの間ヒーローは威張り散らし、自らの計画を大声で叫ぶように強制される。「私と私の盟友達がこの巣穴に潜むグール達を一掃する!! だがしかし、その前に一言言わせてもらいたい」',
  86. 'リラックス:ヒーローが目の前の驚異が気にするほどの物でないと思い1D10ラウンドの間その場に座り込む。彼は葉巻を吸ったり、スキットルで乾杯するのに時間を使うかもしれない。',
  87. 'パニックになって逃亡する:1台のみの車に乗り、例え仲間を置き去りにしていくことになっても、ヒーローは手段さえあれば可能な限り遠くへ行こうとします。1D10ラウンドの間、逃げ続ける。',
  88. '注目を集めたがる:ヒーローは1D10ラウンドの間注目を集めようとする。恐らく無謀な事を行うことだろう。',
  89. 'アルター・エゴ(もう一人の僕!):ヒーローは完全な変化を受け、1D10ラウンドの間、完全に別の人格に入れ替わる。入れ替わった人格はヒーローの性格と真逆のものだ。そのヒーローが親切であれば、もう1人の自分は不親切だ。一方が利己的であれば、もう1人の自分は利他的となる。もし特定のヒーローが永久的な狂気に陥った場合、キーパーは原因である怪物の自我を生み出すことに使用する事もできる。',
  90. '恐怖症:ヒーローは新しい恐怖症に陥る。恐怖症表(PHコマンド)をロールするか、キーパーが恐怖症を1つ選ぶ。恐怖症の原因は存在しなくとも、その探索者は次の1D10ラウンドの間、それがそこにあると思い込む。',
  91. 'マニア:ヒーローは新しいマニアに陥る。マニア表(MAコマンド)をロールするか、キーパーがマニアを1つ選ぶ。その探索者は次の1D10ラウンドの間、自分の新しいマニアに没頭しようとする。',
  92. ].freeze
  93. # 略式の恐怖表
  94. 1 def roll_bms_table()
  95. 3 total_n = @randomizer.roll_once(10)
  96. 3 text = MADNESS_SUMMARY_TABLE[total_n - 1]
  97. 3 time_n = @randomizer.roll_once(10)
  98. 3 return "狂気の発作(サマリー)(#{total_n}) > #{text}(1D10>#{time_n}時間)"
  99. end
  100. 1 MADNESS_SUMMARY_TABLE = [
  101. '健忘症:ヒーローは自分が誰であるかの記憶を失い、パルプのタレントを失い、自分のいる場所に大きな違和感を覚える。彼らの記憶は時間の経過と共にゆっくりと戻る。彼らのパルプのタレントは危機的な状況でのみ戻る。この場合、危機的状況とは誰かの命が晒されているなどの場合と定義する。誰かの命が脅かされるとヒーローは〈幸運〉ロールをう。成功すればタレントは戻る。失敗すれば1D10ラウンド後にもう一度行うことができる。',
  102. '盗難:1D10時間後にヒーローは意識を取り戻す。彼は無傷だ。彼が宝物を持っている場合それが盗まれたかどうかを知るために〈幸運〉ロールを行う。価値のあるものは全て自動的に失われる。',
  103. '暴行:ヒーローは1D10時間後に目覚め、体中が痣や傷だらけであることに気づく。耐久力が半分になる。物は奪われていない。どの様な被害にあったかは、キーパーに委ねられる。',
  104. '暴力:暴力と破壊衝動をヒーローは爆発させる。1D10時間後にヒーローの意識が戻るとき、彼らが行った行動を覚えているかもしれない。ヒーローが誰に対して暴力を振るったか、誰を殺したかはキーパーに委ねられる。',
  105. 'イデオロギー/信念:ヒーローのイデオロギーと信念、背景を証明しようとする。ヒーローは極端に狂い、実証的なやり方でこれらの1つを証明しようとする。一般的にこのような結果はヒーローが人類を傷つけ、正義という名の誇大妄想を抱く事につながる。',
  106. '重要な人々:ヒーローの背景情報を見て関係を持つ重要な人々を参照する。(1D10時間以上)ヒーローはその人物に近づき、その人の為に最善を尽くす。',
  107. '収容:ヒーローは高セキュリティの精神病院または警察の監獄で目を覚ます。彼らはそこで自分が犯した出来事をゆっくりと思い出すかもしれない。',
  108. 'パニック:ヒーローが目覚めると元いた場所から遠く離れた場所にいることに気づく。彼らはエンパイア・ステート・ビルの屋上、ホワイト・ハウスの中、または軍事本部の中心にいるかもしれない。それは注目を集める事になるだろう、何故彼らがその場にいるのかは彼らにもわからない。',
  109. '恐怖症:ヒーロー新たな恐怖症を獲得する。恐怖症表(PHコマンド)をロールするか、キーパーがどれか1つ選ぶ。探索者は1D10時間後に意識を取り戻し、この新たな恐怖症の対象を避けるためにあらゆる努力をしている。',
  110. 'マニア:ヒーローは新たなマニアを獲得する。マニア表(MAコマンド)をロールするか、キーパーがどれか1つ選ぶ。この狂気の発作の間、探索者はこの新たなマニアに完全に溺れているだろう。これがほかの人々に気づかれるかどうかは、キーパーとプレイヤーに委ねられる。',
  111. ].freeze
  112. # キャスティング・ロールのプッシュに失敗した場合
  113. 1 FAILED_CASTING_EFFECTS_TABLE = [
  114. '叙事詩的な雷と稲光。',
  115. '1D6ラウンドの一時的な盲目(成功難易度を変化させる/ペナルティ・ダイスを1つ加える)。',
  116. 'どこかから強い風が吹きつける(幸運ロールに失敗すると紙や本などの軽い持ち物を失う)。',
  117. '壁や床や窓などから輝く緑の粘体が発生する(0/1D3の正気度喪失)',
  118. 'キーパーが選んだ奇妙な幻覚に襲われる(見たものに適した正気度喪失)',
  119. 'その付近の小動物たちが爆発する(0/1D3の正気度喪失)。',
  120. '呪文の使い手の髪が真っ白になる。',
  121. '大きな姿のない悲鳴が聞こえる(0/1の正気度喪失)',
  122. '1D4ラウンドの間、目から血を流す(成功難易度を変化させる/ペナルティ・ダイスを1つ加える)。',
  123. '硫黄の臭いがする。',
  124. '大地が震え、壁に亀裂が入って崩れる。',
  125. '呪文の使い手の手がしおれて、燃え(どちらの手なのか幸運ロールで決定する)、1D2のHPを失う。(キーパーの裁量で、手が一時的に燃えるか(手を使用する必要がある技能ロールとDEXロールのすべてにペナルティ・ダイスが加わる)、または永久にしおれて黒くなる(DEXと手を使用する必要がある技能のすべてを20ポイント減少する。))',
  126. '1D6ラウンドの間、血が空から降る。',
  127. '呪文の使い手は異常に年をとる(+2D10歳と能力値の修正)。',
  128. '呪文の使い手の皮膚が永久的に半透明になる(その呪文の使い手を見た者は1/1D4の正気度喪失)。',
  129. '呪文の使い手は1D10のPOWを獲得するが、1D10の正気度も失う。',
  130. 'クトゥルフ神話の怪物が偶然召喚される。',
  131. 'キーパーはランダムに2つの呪文を選び、両方が発動する(呪文の使い手を中心に)。',
  132. '呪文の使い手と近くの全員が、別の場所に吸い込まれる(キーパーがどこかは決定する)。',
  133. 'クトゥルフ神話の神格が偶然招来される。',
  134. ].freeze
  135. # 狂気のタレント表
  136. 1 INSANE_TALENTS_TABLE = [
  137. '狂気的筋力:「私は無尽蔵の内なる力の蓄えを引き出す!」1つのSTRロールにボーナス・ダイスを1つ得る。ロールが失敗した場合、何かがうまくいかない。キーパーは、ヒーローが負傷した(1D3+ヒーローのDBのダメージを筋断裂等により受ける)か、働きかけたものが壊れるかを選ぶ。',
  138. '狂気的敏捷性:「私の手は目で見えるよりも素早く動く!」1つのDEXロールにボーナス・ダイスを1つ得る。ロールに失敗した場合、何かがうまくいかない。キーパーは、ヒーローが負傷した(1D4のダメージを受ける)か、彼らが働きかけていたものを壊してしまう。',
  139. '狂気的精神力:「私を流れるパワーを感じることができる!」1つのPOWロールにボーナス・ダイスを1つ得る。ロールに失敗した倍、何かがうまくいかない。キーパーは、ヒーローが意識を失うか、達成しようとしていた効果が、意図していた以上にかなり危険になる。',
  140. '狂気的体力:「歯軋りをしても痛みを感じない!」かなりのダメージを受けたときに、ヒーローはCONロールをすることを選ぶかもしれない。成功すれば、苦痛に耐え、ダメージを半減させる。ロールに失敗した場合は、ロールしたダメージを受け、地面へと倒れ、1D3ラウンド無能力化される。',
  141. '狂気的外見:「くそ、私がかわい子ちゃんに!」ヒーローは、どういうわけかとても違って見える。これは純粋に表情と姿勢に現れるか、あるいは彼らの服や髪が何か根本的に時間をかけて変わる(服が魔法のように変わるのではなく、彼らが自分で変える)。APPや魅惑や言いくるめなどの彼らの外見によって影響を受けるかもしれないロールにボーナス・ダイスを1つ得る。この効果は短命だが、1つのシーンや会議などの一定の時間内の全ての交流に適応される。『改善された』外見のためにこのボーナス・ダイスを使用し、ロールに失敗した場合、彼らは社会的な不名誉や悪い結果に苦しめられることになる。',
  142. '狂気的回想力:「私は全てを完全に覚えている!」ヒーローがこれまでに聞いた事実と記憶をすぐに手に入れられる。顔、数字、細部の情報が、情報の洪水の中で彼らの精神に押し寄せてくる。ヒーローが一度聞いたあるいは見たことのありそうな情報を思い出そうとする時の、EDUか知識か技能ロール1つにボーナス・ダイスを1つ得る。ロールに失敗した場合、情報の洪水は多すぎた!1正気度ポイントを失い、1つの狂気の発作に苦しむ。ヒーローがまだ狂気でないのであれば、彼らは今や一時的な狂人となる。',
  143. '狂気的スピード:「私を見ろ、私は弾丸よりも早いぞ!」1つのチェイスに入った時に、ヒーローは移動率を決めるためのCONロールにボーナス・ダイスを1つ得る。ロールが成功すれば、1移動率が上がる。ロールが極限の成功をした場合には、2上がる。ロールが失敗した場合は、彼らは何かをしくじって、少なくとも1D3回の行動を失う。',
  144. '狂気的運転手:「今や私を止められるものなど誰もいない!」あるチェイスにおけるヒーローの全ての運転ロールにボーナス・ダイスを1つ得る。運転ロールが失敗した場合、彼らはどういうわけか(キーパーの裁量で)車両のコントロールを失う。',
  145. '狂気的言語:「いやはや、スワヒリ語の勉強をこれまでしたことはないのですが、これは難しいのでしょうかね?」ヒーローは短期間、全ての現代の言語(あるいは古風なある言語、またはあるクトゥルフ神話の言語)を一時的に理解する。この効果は魔道書を最初に読んだり、会話を行ったり、スピーチを聞けるくらいに十分な長さがある。事実上の技能としては75%だ。新たな言語の使用に技能ロールが必要な場合、その失敗は、ヒーローが1D6日間の間母国語を忘れ、その時に使用された新たな言語が代わりに母国語になるということを意味する。',
  146. '狂気的精度:「私には当たる気しかしないよ!」ヒーローは彼らの銃が空になるまで、全ての火器ロールにボーナス・ダイスを1つ得る。彼らの射撃がターゲットの1つに当たらないか、弾薬がなくなるまで、ボーナス・ダイスを使い続けることができる。その当たらなかった弾丸は当たって欲しくないものに当たる(味方の1人かすごく価値のある何かに、極限の成功(貫通)をしたかのようにダメージを与える)。',
  147. '狂気的脅し:「お前、俺が愉快なんだと思うかい?どこが愉快なんだ?」ヒーローは威圧ロールにボーナスを1つ得る。ロールに失敗した場合、彼らは短期間彼らの行動を制御できなくなる。キーパーが何が起こるか(彼らが暴力的に激怒する(会話している人にダメージを与える可能性がある)か、見くびられ恥を受けるか)を決める。',
  148. '狂気的回避:「蝶のように舞う!」ヒーローは回避ロールに失敗するまで、現在の戦闘シーンにおける全ての回避ロールにボーナス・ダイスを1つ得る。この失敗は、攻撃に自ら突っ込んでいくことを示しており、その場合、攻撃が極限の成功を収めたかのようにダメージを受ける。',
  149. '狂気的方向感覚:「ついて来て、こっちがそうだよ!」ヒーローのプレイヤーはキーパーに彼らがどこに行きたいのか、あるいは何に向かいたいのかを伝える。キーパーはこれが達成されるであろう方向を示す。ヒーローは幸運ロールをし、ロールに失敗した場合は、彼らは何かしらの種類の罠や危険な遭遇へと直進していく。',
  150. '狂気的理解:「ああ、今それが分かった!」ヒーローのプレイヤーはプロットに関する質問をすることができる。「なぜ敵が~をしているの?」、「敵は~によって達成しようとしていることは何です?」、「我々が敵の計画を妨害することができる最良の行動は何です?」、「敵の最大の弱点は何です?」などだ。質問はかなり具体的でなければならず、キーパーは正直に答えるべきである。このタレントは一度しか使用できず、使用すれば失われる。',
  151. '狂気的視界:「光?誰が必要なんだい?」ヒーローは1つの目星ロールにボーナス・ダイスを1つ得る。完全な暗闇の中でさえも、彼らは夕暮れのようにロールすることができる。ロールに失敗した場合、キーパーは、目が敏感になりすぎて痛みが生じる(1D10ラウンドの間事実上に盲目になる)、またはこれから1時間妄想に悩ませられることになるかを決定する。',
  152. '狂気的聴覚:「みんな静かにして、何かカチカチ音がしない?」ヒーローは、1つの聞き耳ロールにボーナス・ダイスを1つ得る。周囲の騒音や他の音によらずに、彼らはその中で最も静かな音でさえも拾うことができる。キーパーは、何らかの突発的なノイズが1D10分間彼らを聴覚障害にするか、またはこれから1時間聴覚的な妄想にとらわれるかを決定する。',
  153. '狂気的隠密:「私のこと見えてないんだよね?」ヒーローは1つのステルスロールにボーナス・ダイスを1つ得る。彼らは猫のような優雅さで移動し、丸見えのような場所にさえ隠れようとするかもしれない。ロールが失敗したのであれば、彼らは誤って何かを壊したり、大きな騒ぎを引き起こす。',
  154. '狂気的獰猛さ:「お前を粉みじんに叩き切ってみせるぜ!」ヒーローは全ての近接攻撃のダメージロールを2回行い、最良の結果を得る。欠点としては、いったん命中すると彼らは止められないことだ!彼らは最後の一撃を与えるまで、攻撃し続ける。これを止めるための方法は2つしかない。彼らが意識不明になるか、誰かが困難難易度の言いくるめか、魅惑か、威圧ロールを彼らに成功させた場合がそうだ(1戦闘ラウンドで、1人の人物のみがこれらの状態のヒーローの1人に試みることができる)。',
  155. '狂気的技能増強:「あんたは私が狂ってると思うのか?だがあんたに教えることができるぞ!」狂気の副作用として、ヒーローはクトゥルフ神話のいくつかの側面を伴う、彼らの技能の1つ(プレイヤーが選び、キーパーが許可を与えたもの)を強化することができる。これはその技能で達成できることの範囲に影響する。ハーバート・ウェストとクロフォード・ティリンギャーストの両方が、これがどのようにその人物に影響を与えるかについての事前研究の良い候補者となる。',
  156. '狂気的技能増強:「あんたは私が狂ってると思うのか?だがあんたに教えることができるぞ!」狂気の副作用として、ヒーローはクトゥルフ神話のいくつかの側面を伴う、彼らの技能の1つ(プレイヤーが選び、キーパーが許可を与えたもの)を強化することができる。これはその技能で達成できることの範囲に影響する。ハーバート・ウェストとクロフォード・ティリンギャーストの両方が、これがどのようにその人物に影響を与えるかについての事前研究の良い候補者となる。',
  157. ].freeze
  158. end
  159. end
  160. end

lib/bcdice/game_system/Raisondetre.rb

96.77% lines covered

86.36% branches covered

93 relevant lines. 90 lines covered and 3 lines missed.
44 total branches, 38 branches covered and 6 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Raisondetre < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Raisondetre'
  7. # ゲームシステム名
  8. 1 NAME = '叛逆レゾンデートル'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'はんきやくれそんてとおる'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. 判定:[判定値]RD[技能][@目標値]
  14. ダメージロール:[ダイス数]DD[装甲]
  15. []内のコマンドは省略可能。
  16. 「判定値」で判定に使用するダイス数を指定。省略時は「1」。0以下も指定可。
  17. 「技能」で有効なダイス数を指定。省略時は「1」。
  18. 達成値はクリティカルを含めて、「最も高くなる」ように計算します。
  19. 「@目標値」指定で、判定の成否を追加表示します。
  20. ダメージロールは[装甲]指定で、有効なダイス数と0の出目の数を表示します。
  21. [装甲]省略時は、ダイス結果のみ表示します。(複数の対象への攻撃時用)
  22. 【書式例】
  23. ・RD → 1Dで達成値を表示。
  24. ・2RD1@8 → 2D(1個選択)で目標値8の判定。
  25. ・-3RD → 1Dでダイスペナルティ-4の判定。
  26. ・4DD2 → 4Dで装甲2のダメージロール。
  27. MESSAGETEXT
  28. 1 def initialize(command)
  29. 25 super(command)
  30. 25 @sort_add_dice = true # ダイスのソート有
  31. end
  32. 1 register_prefix(
  33. '(-)?(\d+)?RD',
  34. '(-)?(\d+)?DD'
  35. )
  36. 1 def eval_game_system_specific_command(command)
  37. 25 then: 20 if command =~ /(-)?(\d+)?RD(\d+)?(@(\d+))?$/i
  38. 20 diceCount = (Regexp.last_match(2) || 1).to_i
  39. 20 else: 16 then: 4 diceCount *= -1 unless Regexp.last_match(1).nil?
  40. 20 choiceCount = (Regexp.last_match(3) || 1).to_i
  41. 20 target = (Regexp.last_match(5) || 0).to_i
  42. 20 return checkRoll(diceCount, choiceCount, target)
  43. else: 5
  44. 5 then: 5 else: 0 elsif command =~ /(-)?(\d+)?DD([1-9])?([+-]\d+)?$/i
  45. 5 diceCount = (Regexp.last_match(2) || 1).to_i
  46. 5 else: 5 then: 0 diceCount *= -1 unless Regexp.last_match(1).nil?
  47. 5 armor = (Regexp.last_match(3) || 0).to_i
  48. 5 then: 3 else: 2 if armor > 0
  49. 3 armor += (Regexp.last_match(4) || 0).to_i
  50. 3 then: 0 else: 3 armor = 1 if armor < 1
  51. 3 then: 0 else: 3 armor = 9 if armor > 9
  52. end
  53. 5 return checkDamage(diceCount, armor)
  54. end
  55. return nil
  56. end
  57. 1 def checkRoll(diceCount, choiceCount, target)
  58. 20 then: 8 if diceCount <= 0
  59. 8 correction = 1 + diceCount * -1
  60. 8 rollCount = 1
  61. else: 12 else
  62. 12 correction = 0
  63. 12 rollCount = diceCount
  64. end
  65. 20 diceArray = @randomizer.roll_barabara(rollCount, 10).sort
  66. 20 diceText = diceArray.join(',')
  67. 76 then: 7 else: 49 diceArray.map! { |x| x == 10 ? 0 : x }
  68. 76 diceArray.map! { |i| i - correction }
  69. 20 diceText2 = diceArray.sort.join(',')
  70. 76 funbleArray = diceArray.select { |i| i <= 1 }
  71. 20 isFunble = (funbleArray.size >= rollCount)
  72. 20 dice = 0
  73. 20 success = 0
  74. 20 else: 10 then: 10 unless isFunble
  75. 10 criticalCount = diceArray.count(0)
  76. 10 critical = criticalCount * 10
  77. 10 choiceArray = diceArray.reverse
  78. 10 choiceArray.delete(0)
  79. 10 choiceArray = choiceArray.slice(0..(choiceCount - 1))
  80. 10 choiceText = choiceArray.join(',')
  81. 10 dice = choiceArray.inject(:+)
  82. 10 success = dice + critical
  83. end
  84. 20 result = "#{rollCount}D10"
  85. 20 then: 8 else: 12 result += "-#{correction}" if correction > 0
  86. 20 result += " > [#{diceText}] > [#{diceText2}] > "
  87. 20 then: 10 if isFunble
  88. 10 result += "達成値:0 (Funble)"
  89. else: 10 else
  90. 10 result += "#{dice}[#{choiceText}]"
  91. 10 then: 3 else: 7 result += "+#{critical}" if critical > 0
  92. 10 result += "=達成値:#{success}"
  93. 10 then: 3 else: 7 result += " (#{criticalCount}Critical)" if critical > 0
  94. end
  95. 20 then: 7 else: 13 if target > 0
  96. 7 result += ">=#{target} "
  97. 7 then: 3 else: 4 result += "【成功】" if success >= target
  98. 7 then: 4 else: 3 result += "【失敗】" if success < target
  99. end
  100. 20 return result
  101. end
  102. 1 def checkDamage(diceCount, armor)
  103. 5 then: 0 if diceCount <= 0
  104. correction = 1 + diceCount * -1
  105. rollCount = 1
  106. else: 5 else
  107. 5 correction = 0
  108. 5 rollCount = diceCount
  109. end
  110. 5 dice_list = @randomizer.roll_barabara(rollCount, 10).sort
  111. 5 diceText = dice_list.join(",")
  112. 30 then: 4 else: 21 diceArray = dice_list.map { |x| x == 10 ? 0 : x }.sort
  113. 5 criticalCount = diceArray.count(0)
  114. 30 diceArray.map! { |i| i - correction }
  115. 5 diceText2 = diceArray.join(",")
  116. 5 result = "#{rollCount}D10"
  117. 5 then: 0 else: 5 result += "-#{correction}" if correction > 0
  118. 5 result += " > [#{diceText}] > [#{diceText2}]"
  119. 5 then: 3 else: 2 if armor > 0
  120. 3 resultArray = []
  121. 3 success = 0
  122. 3 diceArray.each do |i|
  123. 15 then: 6 if i >= armor
  124. 6 resultArray.push(i)
  125. 6 success += 1
  126. else: 9 else
  127. 9 resultArray.push("×")
  128. end
  129. end
  130. 3 resultText = resultArray.join(',')
  131. 3 result += " > [#{resultText}]>=#{armor} 有効数:#{success}"
  132. end
  133. 5 result += " 0=#{criticalCount}個"
  134. 5 return result
  135. end
  136. end
  137. end
  138. end

lib/bcdice/game_system/RecordOfLodossWar.rb

96.15% lines covered

92.86% branches covered

26 relevant lines. 25 lines covered and 1 lines missed.
14 total branches, 13 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class RecordOfLodossWar < Base
  5. 1 ID = 'RecordOfLodossWar'
  6. 1 NAME = 'ロードス島戦記RPG'
  7. 1 SORT_KEY = 'ろおとすとうせんきRPG'
  8. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  9. ●判定
  10.  LW<=(目標値)で判定。
  11.  達成値が目標値の1/10(端数切り上げ)以下であれば大成功。1~10であれば自動成功。
  12.  91~100であれば自動失敗となります。
  13. ●回避判定
  14.  LWD<=(目標値)で回避判定。この時出目が51以上で自動失敗となります。
  15.  判定と回避判定は、どちらもコマンドだけの場合、出目の表示と自動成功と自動失敗の判定のみを行います。
  16. INFO_MESSAGE_TEXT
  17. 1 register_prefix('LW')
  18. 1 def eval_game_system_specific_command(command)
  19. 9 parser = Command::Parser.new("LWD", "LW", round_type: round_type)
  20. .restrict_cmp_op_to(nil, :<=)
  21. 9 cmd = parser.parse(command)
  22. 9 then: 0 else: 9 if cmd.nil? || ![nil, :<=].include?(cmd.cmp_op)
  23. return nil
  24. end
  25. 9 then: 2 else: 7 auto_failure = cmd.command == "LWD" ? 51 : 91
  26. 9 critical = (cmd.target_number.to_f / 10).ceil
  27. 9 dice_value = @randomizer.roll_once(100)
  28. result =
  29. 9 then: 3 if dice_value >= auto_failure
  30. 3 else: 6 "自動失敗(#{auto_failure})"
  31. 6 then: 1 elsif dice_value <= critical
  32. 1 else: 5 "大成功(#{critical})"
  33. 5 then: 1 elsif dice_value <= 10
  34. 1 else: 4 "自動成功"
  35. 4 then: 2 else: 2 elsif cmd.cmp_op
  36. 2 then: 1 else: 1 dice_value <= cmd.target_number ? "成功" : "失敗"
  37. end
  38. sequence = [
  39. 9 "(1D100#{cmd.cmp_op}#{cmd.target_number})",
  40. dice_value.to_s,
  41. result
  42. ].compact
  43. 9 return sequence.join(" > ")
  44. end
  45. end
  46. end
  47. end

lib/bcdice/game_system/RecordOfSteam.rb

96.2% lines covered

87.1% branches covered

79 relevant lines. 76 lines covered and 3 lines missed.
31 total branches, 27 branches covered and 4 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class RecordOfSteam < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'RecordOfSteam'
  7. # ゲームシステム名
  8. 1 NAME = 'Record of Steam'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'れこおとおふすちいむ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. 2S2@1
  14. RecordOfSteam : (2S2@1) > 1,2,3,4 > 1回転 > 成功数2
  15. 4S3@2
  16. RecordOfSteam : (4S3@2) > 2,1,2,4,4,4,2,3,4,5,6,6 > 4回転 > 成功数5
  17. MESSAGETEXT
  18. 1 register_prefix('\d+S\d+')
  19. # サンプルのダイスコマンドは「nSt@c」で n=ダイス個数, t=目標値, c=クリティカル値。@cのみ省略可
  20. 1 def eval_game_system_specific_command(command)
  21. 8 else: 8 then: 0 unless /(\d+)[sS](\d+)(@(\d+))?/i =~ command
  22. return "1"
  23. end
  24. # $x の結果は正規表現マッチングすると新しい値に書き換わってしまうので、
  25. # マッチングした直後に変数に格納してしまうのが大事なポイント!
  26. 8 diceCount = Regexp.last_match(1).to_i
  27. 8 targetNumber = Regexp.last_match(2).to_i
  28. 8 criticalValue = Regexp.last_match(4)
  29. 8 criticalValue ||= 1
  30. 8 criticalValue = criticalValue.to_i
  31. 8 then: 0 else: 8 if diceCount >= 150
  32. return "(多分)無限個なので振れません! ヤメテクダサイ、(プロセスが)死んでしまいますっ"
  33. end
  34. 8 then: 0 else: 8 if criticalValue >= 3
  35. return "(多分)無限個なので振れません! ヤメテクダサイ、(プロセスが)死んでしまいますっ"
  36. end
  37. 8 specialValue = criticalValue
  38. 8 rollResult, successCount, roundCount, specialCount, fumbleCount = getDiceRollResult(diceCount, targetNumber, criticalValue, specialValue)
  39. 8 output = "(#{command}) > #{rollResult}"
  40. 8 roundCountText = getRoundCountText(roundCount)
  41. 8 successText = getSuccessText(successCount)
  42. 8 specialText = getSpecialText(specialCount)
  43. 8 fumbleText = getFumbleText(fumbleCount)
  44. 8 result = "#{output}#{roundCountText}#{specialText}#{successText}#{fumbleText}"
  45. 8 return result
  46. end
  47. 1 def getDiceRollResult(diceCount, targetNumber, criticalValue, specialValue)
  48. 8 successCount = 0
  49. 8 roundCount = 0
  50. 8 rollResult = ""
  51. 8 specialCount = 0
  52. 8 specialFlag = false
  53. 8 fumbleCount = 0
  54. 8 fumbleFlag = false
  55. 8 body: 13 while diceCount > 0
  56. 13 diceList = @randomizer.roll_barabara(diceCount, 6)
  57. 13 diceListText = diceList.join(",")
  58. 13 then: 5 else: 8 rollResult += "," if rollResult != ""
  59. 13 rollResult += diceListText
  60. 13 then: 4 else: 9 if diceList.uniq.length == 1 && roundCount == 0
  61. 4 then: 1 if diceList.uniq.first <= specialValue
  62. 1 else: 3 specialFlag = true
  63. 3 then: 3 else: 0 elsif diceList.uniq.first == 6
  64. 3 fumbleFlag = true
  65. end
  66. end
  67. 13 debug("diceList", diceList)
  68. 13 then: 1 if specialFlag
  69. 1 specialCount = 1
  70. 1 successCount = diceCount * 3
  71. 1 else: 12 return rollResult, successCount, roundCount, specialCount, fumbleCount
  72. 12 then: 3 else: 9 elsif fumbleFlag
  73. 3 fumbleCount = 1
  74. 3 return rollResult, successCount, roundCount, specialCount, fumbleCount
  75. end
  76. 9 diceCount = 0
  77. 9 diceList.map do |diceValue|
  78. 28 debug("diceValue", diceValue)
  79. 28 debug("criticalValue", criticalValue)
  80. 28 debug("specialValue", specialValue)
  81. 28 then: 8 else: 20 if diceValue <= criticalValue
  82. 8 diceCount += 2
  83. 8 roundCount += 1
  84. end
  85. 28 then: 13 else: 15 successCount += 1 if diceValue <= targetNumber
  86. end
  87. end
  88. 4 return rollResult, successCount, roundCount, specialCount, fumbleCount
  89. end
  90. 1 def getRoundCountText(roundCount)
  91. 8 then: 5 else: 3 if roundCount <= 0
  92. 5 return ""
  93. end
  94. 3 return " > #{roundCount}回転"
  95. end
  96. 1 def getSuccessText(successCount)
  97. 8 then: 5 else: 3 if successCount > 0
  98. 5 return " > 成功数#{successCount}"
  99. end
  100. 3 return " > 失敗"
  101. end
  102. 1 def getSpecialText(specialCount)
  103. 8 then: 1 else: 7 if specialCount == 1
  104. 1 return " > スペシャル"
  105. end
  106. end
  107. 1 def getFumbleText(fumbleCount)
  108. 8 then: 3 else: 5 if fumbleCount == 1
  109. 3 return " > ファンブル"
  110. end
  111. end
  112. end
  113. end
  114. end

lib/bcdice/game_system/Revulture.rb

100.0% lines covered

93.1% branches covered

53 relevant lines. 53 lines covered and 0 lines missed.
29 total branches, 27 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Revulture < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Revulture'
  7. # ゲームシステム名
  8. 1 NAME = '光砕のリヴァルチャー'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'こうさいのりうあるちやあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~HELP
  13. ■アタック判定( xAT, xATK, xATTACK )
  14. x: ダイス数(加算 + と除算 / を使用可能)
  15. 例) 3AT, 4ATK, 5+6ATTACK, 15/2AT
  16. □アタック判定 目標値つき( xAT<=y, xATK<=y, xATTACK<=y )
  17. x: ダイス数(加算 + と除算 / を使用可能)
  18. y: 目標値( 1 以上 6 以下。加算 + を使用可能)
  19. 例) 3AT<=4, 3AT<=2+1
  20. □アタック判定 目標値&追加ダメージつき( xAT<=y[>=a:+b], xATK<=y[>=a:+b], xATTACK<=y[z] )
  21. x: ダイス数(加算 + と除算 / を使用可能)
  22. y: 目標値( 1 以上 6 以下。加算 + を使用可能)
  23. z: 追加ダメージの規則(詳細は後述)(※複数同時に指定可能)
  24. ▽追加ダメージの規則 [a:+b]
  25. a: ヒット数が a なら
  26.  =a (ヒット数が a に等しい)
  27.  >=a (ヒット数が a 以上)
  28. b: ダメージを b 点追加
  29. 例) 3AT<=4[>=2:+3] #ルールブックp056「グレングラントAR」
  30. 例) 2AT<=4[=1:+5][>=2:+8] #ルールブックp067「ファーボル・ドラゴンブレス」
  31. HELP
  32. 1 ATTACK_ROLL_REG = %r{^(\d+([+/]\d+)*)?AT(TACK|K)?(<=([1-6](\+\d)*))?((\[>?=\d+:\+\d+\])+)?}i.freeze
  33. 1 register_prefix('\d+([+\/]\d+)*AT')
  34. 1 def eval_game_system_specific_command(command)
  35. 38 then: 38 else: 0 if (m = ATTACK_ROLL_REG.match(command))
  36. 38 roll_attack(m[1], m[5], m[7])
  37. end
  38. end
  39. 1 private
  40. 1 def roll_attack(dice_count_expression, border_expression, additional_damage_rules)
  41. 38 dice_count = Arithmetic.eval(dice_count_expression, RoundType::FLOOR)
  42. 38 then: 26 else: 12 border = Arithmetic.eval(border_expression, RoundType::FLOOR).clamp(1, 6) if border_expression
  43. 38 command = make_command_text(dice_count, border, additional_damage_rules)
  44. 38 then: 5 if dice_count <= 0
  45. 5 else: 33 return "#{command} > ダイス数が 0 です"
  46. 33 then: 1 else: 32 elsif border.nil? && additional_damage_rules
  47. 1 return "#{command} > 目標値が指定されていないため、追加ダメージを算出できません"
  48. end
  49. 32 dices = @randomizer.roll_barabara(dice_count, 6).sort
  50. 32 critical_hit_count = dices.count(1)
  51. 106 then: 24 else: 8 hit_count = dices.count { |dice| dice <= border } + critical_hit_count if border
  52. 32 damage = calc_damage(hit_count, additional_damage_rules)
  53. 32 message_elements = []
  54. 32 message_elements << command
  55. 32 message_elements << dices.join(',')
  56. 32 then: 7 else: 25 message_elements << "クリティカル #{critical_hit_count}" if critical_hit_count > 0
  57. 32 then: 24 else: 8 message_elements << "ヒット数 #{hit_count}" if hit_count
  58. 32 then: 10 else: 22 message_elements << "ダメージ #{damage}" if damage
  59. 32 Result.new(message_elements.join(' > ')).tap do |r|
  60. 32 then: 24 else: 8 r.condition = hit_count > 0 if hit_count
  61. 32 r.critical = critical_hit_count > 0
  62. end
  63. end
  64. 1 def make_command_text(dice_count, border, additional_damage_rules)
  65. 38 command = "#{dice_count}attack"
  66. 38 then: 26 else: 12 command += "<=#{border}" if border
  67. 38 then: 13 else: 25 command += additional_damage_rules if additional_damage_rules
  68. 38 "(#{command})"
  69. end
  70. 1 def calc_damage(hit_count, additional_damage_rules)
  71. 32 else: 10 then: 22 return nil unless additional_damage_rules
  72. 10 damage = hit_count
  73. 10 parse_additional_damage_rules(additional_damage_rules).each do |rule|
  74. 13 then: 5 else: 8 if rule[:condition].call(hit_count)
  75. 5 damage += rule[:additinal_damage]
  76. end
  77. end
  78. 10 damage
  79. end
  80. 1 def parse_additional_damage_rules(source)
  81. 10 source.scan(/\[(>?=)(\d+):\+(\d+)\]/).map do |matched|
  82. {
  83. 13 condition: make_additional_damage_condition(matched[0], matched[1].to_i),
  84. additinal_damage: matched[2].to_i,
  85. }
  86. end
  87. end
  88. 1 def make_additional_damage_condition(comparer, comparing_target)
  89. 13 else: 0 case comparer
  90. when: 6 when '='
  91. 12 lambda { |hit_count| hit_count == comparing_target }
  92. when: 7 when '>='
  93. 14 lambda { |hit_count| hit_count >= comparing_target }
  94. end
  95. end
  96. end
  97. end
  98. end

lib/bcdice/game_system/RogueLikeHalf.rb

100.0% lines covered

94.29% branches covered

89 relevant lines. 89 lines covered and 0 lines missed.
35 total branches, 33 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class RogueLikeHalf < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'RogueLikeHalf'
  7. # ゲームシステム名
  8. 1 NAME = 'ローグライクハーフ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ろおくらいくはあふ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGETEXT
  13. ■判定 RH+x>=t x:技量点 t:達成値(威力)
  14. 例)RH+1>=5: ダイスを1個振って、技量点1,達成値5の結果を表示(クリティカル・ファンブルも表示)
  15. ■D33 D33+x x:修正値
  16. 例)D33: 3面ダイスを2個振って、その結果を表示。
  17. ■宝物表 NTT+x x:修正値
  18. INFO_MESSAGETEXT
  19. 1 def initialize(command)
  20. 16 super(command)
  21. 16 @sort_barabara_dice = true # バラバラロール(Bコマンド)でソート有
  22. end
  23. 1 def eval_game_system_specific_command(command)
  24. 16 resolute_action(command) ||
  25. resolute_d33(command) ||
  26. roll_table_command(command)
  27. end
  28. 1 private
  29. 1 def with_symbol(number)
  30. 17 then: 10 if number == 0
  31. 10 else: 7 return "+0"
  32. 7 then: 5 elsif number > 0
  33. 5 return "+#{number}"
  34. else: 2 else
  35. 2 return number.to_s
  36. end
  37. end
  38. # 判定ロール
  39. # @param [String] command
  40. # @return [Result]
  41. 1 def get_result_of_action(total, die, target)
  42. 6 then: 1 if die == 6
  43. 1 else: 5 return Result.critical("クリティカル")
  44. 5 then: 1 elsif die == 1
  45. 1 else: 4 return Result.fumble("ファンブル")
  46. 4 then: 3 elsif total >= target
  47. 3 return Result.success("成功")
  48. else: 1 else
  49. 1 return Result.failure("失敗")
  50. end
  51. end
  52. 1 def resolute_action(command)
  53. 16 m = /RH([+-]\d)*(>=(\d+))?/.match(command)
  54. 16 else: 6 then: 10 return nil unless m
  55. 6 then: 1 else: 5 modify = m[1] ? Arithmetic.eval(m[1], @round_type) : 0
  56. 6 target = m[3].to_i
  57. 6 then: 1 else: 5 target = 4 if target == 0
  58. 6 die = @randomizer.roll_once(6)
  59. 6 die_text = die.to_s
  60. 6 total = die + modify
  61. 6 result = get_result_of_action(total, die, target)
  62. 6 command_text = "(RH#{with_symbol(modify)}>=#{target})"
  63. sequence = [
  64. 6 command_text,
  65. "[#{die_text}]#{with_symbol(modify)}",
  66. total,
  67. result.text,
  68. ].compact
  69. 6 result.text = sequence.join(" > ")
  70. 6 return result
  71. end
  72. # D33ロール
  73. # @param [String] command
  74. # @return [Result]
  75. 1 def resolute_d33(command)
  76. 10 m = /D33([+-]\d+)*/.match(command)
  77. 10 else: 6 then: 4 return nil unless m
  78. 6 then: 5 else: 1 modify = m[1] ? Arithmetic.eval(m[1], @round_type) : 0
  79. 6 dice = @randomizer.roll_barabara(2, 3)
  80. 6 dice_text = dice.join("")
  81. 6 dice_total = dice[0] * 3 + dice[1] + modify
  82. 6 then: 1 else: 5 dice_total = 12 if dice_total > 12
  83. 6 then: 1 else: 5 dice_total = 4 if dice_total < 4
  84. 6 p = dice_total.divmod(3)
  85. 6 then: 3 else: 3 if p[1] == 0
  86. 3 p[0] = p[0] - 1
  87. 3 p[1] = 3
  88. end
  89. 6 total = p[0] * 10 + p[1]
  90. sequence = [
  91. 6 "(#{command})",
  92. dice_text,
  93. ].compact
  94. 6 then: 5 else: 1 if modify != 0
  95. sequence = [
  96. 5 "(#{command})",
  97. "#{dice_text}#{with_symbol(modify)}",
  98. total,
  99. ].compact
  100. end
  101. 6 return Result.new(sequence.join(" > "))
  102. end
  103. 1 def roll_table_command(command)
  104. 4 command = command.upcase
  105. 4 result = []
  106. 4 m = /([A-Z]+)(([+]|-)(\d+))?/.match(command)
  107. 4 else: 4 then: 0 return result unless m
  108. 4 command = m[1]
  109. 4 operator = m[3]
  110. 4 value = m[4].to_i
  111. 4 return get_another_table_result(command, operator, value)
  112. end
  113. 1 def get_another_table_result(command, operator, value)
  114. 4 result = ""
  115. 4 table_name = command
  116. 4 table = TABLES[table_name]
  117. 4 then: 0 else: 4 return result if table.nil?
  118. 4 index = get_table_index(operator, value, 1, 6)
  119. 4 info = table.choice(index)
  120. 4 result = "#{info.table_name}:#{info.value}:#{info.body}"
  121. 4 return result
  122. end
  123. 1 def get_table_index(operator, value, dice_count, dice_type)
  124. 4 modify = 0
  125. 4 else: 2 case operator
  126. when: 1 when "+"
  127. 1 modify = value
  128. when: 1 when "-"
  129. 1 modify = value * -1
  130. end
  131. 4 index = @randomizer.roll_sum(dice_count, dice_type)
  132. 4 index += modify
  133. 4 index = [index, dice_count * 1].max
  134. 4 index = [index, dice_count * dice_type + 1].min
  135. 4 return index
  136. end
  137. TABLES = {
  138. 1 "NTT" => DiceTable::Table.new(
  139. "宝物表",
  140. "1D6",
  141. [
  142. "金貨1枚",
  143. "1d6枚の金貨",
  144. "2d6枚の金貨(下限は金貨5枚)",
  145. "1個のアクセサリー(1d6×1d6枚の金貨と同等の価値)",
  146. "1個の宝石・小(1d6×5枚の金貨と同等の価値。下限は金貨15枚の価値)",
  147. "1個の宝石・大(2d6×5枚の金貨と同等の価値。下限は金貨30枚の価値)",
  148. "【魔法の宝物表】でダイスロールを行うこと。",
  149. ]
  150. )
  151. }.freeze
  152. 1 register_prefix('RH', 'D33', TABLES.keys)
  153. end
  154. end
  155. end

lib/bcdice/game_system/RokumonSekai2.rb

96.49% lines covered

86.36% branches covered

57 relevant lines. 55 lines covered and 2 lines missed.
22 total branches, 19 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class RokumonSekai2 < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'RokumonSekai2'
  7. # ゲームシステム名
  8. 1 NAME = '六門世界RPG セカンドエディション'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ろくもんせかいRPG2'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定
  14. aRSm<=t
  15. 能力値a,修正値m,目標値tで判定ロールを行います。
  16. Rコマンド(3R6m<=t[a])に読み替えます。
  17. 成功度、評価、ボーナスダイスを自動表示します。
  18.  例) 3RS+1<=9 3R6+1<=9[3]
  19. INFO_MESSAGE_TEXT
  20. 1 register_prefix('\d+RS', '3R6')
  21. 1 def initialize(command)
  22. 50 super(command)
  23. 50 @sort_add_dice = true
  24. end
  25. 1 def replace_text(string)
  26. 80 string = string.gsub(/(\d+)RS([+-][+\-\d]+)<=(\d+)/i) { "3R6#{Regexp.last_match(2)}<=#{Regexp.last_match(3)}[#{Regexp.last_match(1)}]" }
  27. 60 string = string.gsub(/(\d+)RS<=(\d+)/i) { "3R6<=#{Regexp.last_match(2)}[#{Regexp.last_match(1)}]" }
  28. 50 return string
  29. end
  30. 1 def eval_game_system_specific_command(string)
  31. 50 string = replace_text(string)
  32. 50 else: 50 then: 0 unless /3R6([+\-\d]*)<=(\d+)\[(\d+)\]/i =~ string
  33. return nil
  34. end
  35. 50 modText = Regexp.last_match(1)
  36. 50 target = Regexp.last_match(2).to_i
  37. 50 abl = Regexp.last_match(3).to_i
  38. 50 mod = 0
  39. 50 then: 50 else: 0 if modText
  40. 50 mod = ArithmeticEvaluator.eval(modText)
  41. end
  42. 50 dstr, suc, sum = rokumon2_roll(mod, target, abl)
  43. 50 output = "#{sum}[#{dstr}] > #{suc} > 評価#{rokumon2_suc_rank(suc)}"
  44. 50 then: 38 else: 12 if suc != 0
  45. 38 output += "(+#{suc}d6)"
  46. end
  47. 50 output = "(#{string}) > #{output}"
  48. 50 return output
  49. end
  50. 1 def rokumon2_roll(mod, target, abl)
  51. 50 suc = 0
  52. 50 dice = @randomizer.roll_barabara(3 + mod.abs, 6).sort
  53. 50 dicestr = dice.join(",")
  54. 50 mod.abs.times do |_i|
  55. 130 then: 0 if mod < 0
  56. dice.shift
  57. else: 130 else
  58. 130 dice.pop
  59. end
  60. end
  61. 50 cnt5 = 0
  62. 50 cnt2 = 0
  63. 50 sum = 0
  64. 50 dice.each do |die1|
  65. 150 then: 25 else: 125 cnt5 += 1 if die1 >= 5
  66. 150 then: 78 else: 72 cnt2 += 1 if die1 <= 2
  67. 150 then: 83 else: 67 suc += 1 if die1 <= abl
  68. 150 sum += die1
  69. end
  70. 50 then: 29 if sum < target
  71. 29 else: 21 suc += 2
  72. 21 then: 4 else: 17 elsif sum == target
  73. 4 suc += 1
  74. end
  75. 50 then: 1 else: 49 suc = 0 if cnt5 >= 3
  76. 50 then: 10 else: 40 suc = 5 if cnt2 >= 3
  77. 50 return dicestr, suc, sum
  78. end
  79. 1 def rokumon2_suc_rank(suc)
  80. 50 suc_rank = ['E', 'D', 'C', 'B', 'A', 'S']
  81. 50 return suc_rank[suc]
  82. end
  83. end
  84. end
  85. end

lib/bcdice/game_system/RoleMaster.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class RoleMaster < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'RoleMaster'
  7. # ゲームシステム名
  8. 1 NAME = 'ロールマスター'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ろおるますたあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = "上方無限ロール(xUn)の境界値を96にセットします。\n"
  13. 1 def initialize(command)
  14. 2 super(command)
  15. 2 @upper_dice_reroll_threshold = 96
  16. end
  17. end
  18. end
  19. end

lib/bcdice/game_system/RuinBreakers.rb

95.45% lines covered

86.36% branches covered

66 relevant lines. 63 lines covered and 3 lines missed.
22 total branches, 19 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/arithmetic_evaluator'
  3. 1 require 'bcdice/dice_table/table'
  4. 1 require 'bcdice/dice_table/range_table'
  5. 1 module BCDice
  6. 1 module GameSystem
  7. 1 class RuinBreakers < Base
  8. # ゲームシステムの識別子
  9. 1 ID = 'RuinBreakers'
  10. # ゲームシステム名
  11. 1 NAME = 'ルーインブレイカーズ'
  12. # ゲームシステム名の読みがな
  13. 1 SORT_KEY = 'るういんふれいかあす'
  14. # ダイスボットの使い方
  15. 1 HELP_MESSAGE = <<~MESSAGETEXT
  16. ■ 基本判定 (RBx@y#z)
  17. x:成功率、y:クリティカル値(省略可)、z:ファンブル値(省略可)
  18. 1D100を振って、成功率に応じて成功/失敗/クリティカル/ファンブルの判定を行います。(P.60)
  19. クリティカル値を省略した場合は成功率の5分の1(切り捨て、最低1)
  20. ファンブル値を省略した場合は、成功率が99以下の場合は96、100以上の場合は99
  21. 例) RB32, RB(45+20)/2, RB30@10, RB35+20#90, RB40-20+10@10#90
  22. ■ FPへのダメージ (FPDx)
  23. x:破滅ポイント
  24. ルーインブレイクロール失敗時やラウンド終了時に、残っている
  25. 破滅ポイントに応じて発生するダメージのダイスロールを行います。(P.91,92)
  26. 例) FPD23
  27. ■ FPの回復 (FPRx)
  28. x:破滅ポイント
  29. ルーインブレイク成功時に発生する、FPの回復量を決定するダイスロールを行います。(P.93)
  30. 例) FPR29
  31. ■ 各種表
  32. ・ポジティブ感情表 (PE)
  33. ・ネガティブ感情表 (NE)
  34. ・デウス・エクス・マキナ表 (DXM)
  35. ・断罪チャート (JC)
  36. ・破滅のイヤな感じ表 (RDF)
  37. ・トラブルチャート/トラブル解決チャート (TC)
  38. ・ドタバタアクション表 (DA)
  39. MESSAGETEXT
  40. 1 def eval_game_system_specific_command(command)
  41. 34 case command
  42. when: 14 when /^RB/
  43. 14 check_roll(command)
  44. when: 3 when /^FPD/
  45. 3 roll_fp_damage(command)
  46. when: 3 when /^FPR/
  47. 3 roll_fp_recovery(command)
  48. else: 14 else
  49. 14 roll_tables(command, TABLES)
  50. end
  51. end
  52. 1 private
  53. 1 def check_roll(command)
  54. 14 m = %r{^RB(-?\d+([+\-*/]\d+)*)(@(\d+))?(#(\d+))?$}.match(command)
  55. 14 else: 14 then: 0 unless m
  56. return nil
  57. end
  58. 14 success_rate = ArithmeticEvaluator.eval(m[1])
  59. 14 then: 4 else: 10 critical_border = m[4]&.to_i || [success_rate / 5, 1].max
  60. 14 then: 4 else: 10 then: 8 else: 2 fumble_border = m[6]&.to_i || (success_rate < 100 ? 96 : 99)
  61. 14 total = @randomizer.roll_once(100)
  62. 14 result = Result.new
  63. compare_result =
  64. 14 then: 4 if total >= fumble_border
  65. 4 result.fumble = true
  66. 4 result.failure = true
  67. 4 else: 10 'ファンブル'
  68. 10 then: 3 elsif total == 1 || total <= critical_border
  69. 3 result.critical = true
  70. 3 result.success = true
  71. 3 else: 7 'クリティカル'
  72. 7 then: 5 elsif total <= success_rate
  73. 5 result.success = true
  74. 5 '成功'
  75. else: 2 else
  76. 2 result.failure = true
  77. 2 '失敗'
  78. end
  79. sequence = [
  80. 14 "(1D100<=#{success_rate}@#{critical_border}##{fumble_border})",
  81. total,
  82. compare_result
  83. ]
  84. 14 result.text = sequence.join(" > ")
  85. 14 result
  86. end
  87. 1 def roll_fp_damage(command)
  88. 3 m = /^FPD(\d+)$/.match(command)
  89. 3 else: 3 then: 0 unless m
  90. return nil
  91. end
  92. 3 ruin_point = m[1].to_i
  93. 3 ruin_point_tens, ruin_point_ones = ruin_point.divmod(10)
  94. 3 dice_list = @randomizer.roll_barabara(1 + ruin_point_tens, 10)
  95. 3 total = dice_list.sum()
  96. 3 dice_str = dice_list.join(",")
  97. sequence = [
  98. 3 "((1+#{ruin_point_tens})D10+#{ruin_point_ones})",
  99. "#{total}[#{dice_str}]+#{ruin_point_ones}",
  100. "#{total + ruin_point_ones}ダメージ"
  101. ]
  102. 3 return sequence.join(" > ")
  103. end
  104. 1 def roll_fp_recovery(command)
  105. 3 m = /^FPR(\d+)$/.match(command)
  106. 3 else: 3 then: 0 unless m
  107. return nil
  108. end
  109. 3 ruin_point = m[1].to_i
  110. 3 dice_count = ruin_point.fdiv(10).ceil
  111. 3 dice_list = @randomizer.roll_barabara(dice_count, 10)
  112. 3 total = dice_list.sum()
  113. 3 dice_str = dice_list.join(",")
  114. sequence = [
  115. 3 "(#{dice_count}D10)",
  116. "#{total}[#{dice_str}]",
  117. "#{total}回復"
  118. ]
  119. 3 return sequence.join(" > ")
  120. end
  121. TABLES = {
  122. 1 "PE" => DiceTable::RangeTable.new(
  123. "ポジティブ感情表",
  124. "1D100",
  125. [
  126. [1..5, "【希望】相手はまるで自分の過去、あるいは未来を見ているように感じる。"],
  127. [6..10, "【礼儀】相手に礼を尽くすべきだとあなたは考えている。"],
  128. [11..15, "【家族】相手とは家族のような関係となる。"],
  129. [16..20, "【恩人】相手から助けを受けたことがある。それは大事な思い出だ。"],
  130. [21..25, "【友人】相手とはなんとなくウマが合う。一緒にいると楽しい。"],
  131. [26..30, "【信用】相手は信用できる人物だと思う。"],
  132. [31..35, "【仲間】相手は同じ目的を持つ仲間だ。"],
  133. [36..40, "【庇護】相手のことを助けてあげたいと思っている。"],
  134. [41..45, "【尊敬】相手の行動、思考、思想などを尊敬している。"],
  135. [46..50, "【憧れ】相手の生き方、外見、能力などになんとなく憧れている。"],
  136. [51..55, "【好意】相手の主張、外見、生き方などに好意を抱いている。"],
  137. [56..60, "【忠義】相手に対して真摯に忠実でありたいと思っている。"],
  138. [61..65, "【目標】相手はあなたにとっての目標であり、理想の存在だ。"],
  139. [66..70, "【借り】相手から助けを受けた。それはいつか返すべき、借りだ。"],
  140. [71..75, "【貸し】相手には貸しがある。別に返してもらおうとは思っていない。"],
  141. [76..80, "【腐れ縁】相手は昔から何かというと縁がある。この縁は今も続いている。"],
  142. [81..85, "【相性】相手とはなんとなくうまくいく。相性がいいようだ。"],
  143. [86..90, "【有為】相手はあなたにとって益をもたらす人物だ、そう考えている。"],
  144. [91..95, "【秘密】相手の秘密を知っている。あるいはお互い秘密を共有している。"],
  145. [96..100, "【好敵手】相手のことを好敵手、ライバルだと思っている。"],
  146. # [101, "【任意】相手と相談の上で関係を設定すること。"],
  147. ]
  148. ),
  149. "NE" => DiceTable::RangeTable.new(
  150. "ネガティブ感情表",
  151. "1D100",
  152. [
  153. [1..5, "【同族嫌悪】1日に自分の忌むべき過去、あるいは自分自身を見ているように感じる。"],
  154. [6..10, "【侮蔑】相手を蔑む気持ちがある。どうにも、気に入らない。"],
  155. [11..15, "【反発】相手の主張や行動などに反発を感じる。相手を受け入れることに抵抗がある。"],
  156. [16..20, "【わだかまり】相手には言葉にしにくいもやもやとした感情を持っている。"],
  157. [21..25, "【隔たり】相手とはなんとなくウマが合わない。一緒にいても面白くない。"],
  158. [26..30, "【疑惑】相手は信用できない人物だと思っている。"],
  159. [31..35, "【裏切り】相手に裏切られたという気持ちがある。"],
  160. [36..40, "【妨害】相手のことを気に入らず、何かあれば、邪魔したいと思っている。"],
  161. [41..45, "【侮辱】相手の行動、思考、思想などを嫌悪している。"],
  162. [46..50, "【うらやみ】相手の生き方、外見、能力などをうらやんでいる。"],
  163. [51..55, "【害意】相手の主張、外見、生き方などを嫌い、害を与えたいと思っている。"],
  164. [56..60, "【不快】相手を不快な人間だと思っている。生理的に受け付けない。"],
  165. [61..65, "【反面】相手を反面教師としている。ああはなるまい、と。"],
  166. [66..70, "【詐欺】相手に騙されているように思う。何か嘘を吐かれているように思うのだ。"],
  167. [71..75, "【搾取】相手に自分の何かを奪われているような怒りを感じる。"],
  168. [76..80, "【悪縁】相手は昔から縁がある。この縁を絶ちきりたいと思っている。"],
  169. [81..85, "【相性】相手とはなんとなくうまくいかない。残念だが相性が悪い。"],
  170. [86..90, "【害悪】相手はあなたにとって害をもたらす、そう思っている。"],
  171. [91..95, "【怨恨】相手に恨みを持っている。この恨みを晴らす日は来るだろうか。"],
  172. [96..100, "【仇敵】相手のことを倒すべき相手と思っている。"],
  173. # [101, "【任意】相手と相談の上で関係を設定すること。"],
  174. ]
  175. ),
  176. "DXM" => DiceTable::RangeTable.new(
  177. "デウス・エクス・マキナ表",
  178. "1D10",
  179. [
  180. [1..2, "神降臨。エンディングフェイズに効果を発揮する。あなたの願いはかなう。願いの内容はGMと相談して決定すること。"],
  181. [3..4, "逃走。状況を無視してあなた以外のキャストはシーンから退場できる。"],
  182. [5..6, "命の雫。あなた以外のキャストのFPが3D10点だけ回復する。"],
  183. [7..8, "天変地異。巨大な嵐や地震、雷雨などが発生し、周囲は大混乱に陥る。トループやエキストラはシーン終了まで何も行なえない(戦闘不能として扱う)。"],
  184. [9..10, "不思議なことが起こった。あなたのFPが完全に回復する。"],
  185. ]
  186. ),
  187. "JC" => DiceTable::Table.new(
  188. "断罪チャート",
  189. "1D10",
  190. [
  191. "【国王/女王】国レベルの代表者が現われて、あなたの主張を支持してくれる。",
  192. "【王子/王女】王子や王女といった国で知らぬ者がないような存在が、あなたの主張を支持してくれる。",
  193. "【高位聖職者】高位の聖職者が、あなたの主張を支持してくれる。",
  194. "【有力貴族】有力貴族が、あなたの主張を支持してくれる。",
  195. "【有力市民】有力市民が、あなたの主張を支持してくれる。",
  196. "【豪商】豪商が、あなたの主張を支持してくれる。",
  197. "【現役学生たち】アカデミーの学生たちが、あなたの主張を支持してくれる。",
  198. "【OB、OGたち】アカデミーのOBやOGが、あなたの主張を支持してくれる。",
  199. "【多くの人々】名も知れぬ多くの人々が、あなたの主張を支持してくれる。",
  200. "【外国の王侯貴族】外国の代表者が現われて、あなたの主張を支持してくれる。",
  201. # "【任意】GMと相談して後ろ盾となる人物を決定する。",
  202. ]
  203. ),
  204. "RDF" => DiceTable::RangeTable.new(
  205. "破滅のイヤな感じ表",
  206. "1D100",
  207. [
  208. [1..5, "【水中で拘束】\n演出:水中で長い髪の毛が全身に絡みついて動きが重くなるような感覚。\nルーインブレイク成功:重い拘束から解き放たれたような快感。"],
  209. [6..10, "【鈍痛】\n演出:こめかみから長い釘を差し込まれているような感覚。\nルーインブレイク成功:痛みが消えてなくなる安堵感。"],
  210. [11..15, "【酸欠】\n演出:空気が薄くなり呼吸をしても息苦しさが消えない感覚。\nルーインブレイク成功:清浄な空気を吸った時の快感。"],
  211. [16..20, "【ヘッドロック】\n演出:頭を締め上げられているような感覚。\nルーインブレイク成功:痛みから逃れられた安心感。"],
  212. [21..25, "【悪寒】\n演出:背中が冷やりとして悪寒が全身を突き抜けるような感覚。\nルーインブレイク成功:悪寒が鎮まった平穏感。"],
  213. [26..30, "【熱病】\n演出:熱病で浮かされたように頭がぼうっとする感覚。\nルーインブレイク成功:落ち着きを取り戻した安息感。"],
  214. [31..35, "【高所恐怖】\n演出:目もくらむような断崖の際に立たされたような感覚。\nルーインブレイク成功:落下の恐怖から逃れた安堵感。"],
  215. [36..40, "【ガラスの破片】\n演出:砕けた散ったガラスの破片を踏み続けるような感覚。\nルーインブレイク成功:幻の痛みが消えていく安心感。"],
  216. [41..45, "【ジャリ感】\n演出:口の中に砂を詰め込まれたような感覚。\nルーインブレイク成功:口の中がすっきりしたような清浄感。"],
  217. [46..50, "【耳鳴り】\n演出:耳をふさいでも聞こえる耳鳴りが響き続けているような感覚。\nルーインブレイク成功:異音が消えた平安感。"],
  218. [51..55, "【孤独】\n演出:虚空にただひとり浮かんでいるような孤独な感覚。\nルーインブレイク成功:孤立から脱した安心感。"],
  219. [56..60, "【落下感】\n演出:高所から落ち続けているような感覚。\nルーインブレイク成功:地に足のついた安定感。"],
  220. [61..65, "【暗所恐怖】\n演出:明るいはずなのに周囲が真っ暗で何も見えない不安な感覚。\nルーインブレイク成功:周囲がハッキリ見える安息感。"],
  221. [66..70, "【擦過】\n演出:心の表面をザラザラとしたもので削られているような感覚。\nルーインブレイク成功:痛みから逃れられた安楽感。"],
  222. [71..75, "【幻聴】\n演出:周囲に人がいて、絶えず自分の悪口を囁きあっているような感覚。\nルーインブレイク成功:周囲への恐怖が消えた平穏感。"],
  223. [76..80, "【異臭】\n演出:不快な香りが漂ってくるような感覚。\nルーインブレイク成功:異臭を感じなくなった清浄感。"],
  224. [81..85, "【健忘感】\n演出:何かを忘れていて、それが何かは思い出せないような感覚。\nルーインブレイク成功:忘れごとを思い出せたときの開放感。"],
  225. [86..90, "【杞憂】\n演出:天が崩れていつ落ちてくるかわからない感覚。\nルーインブレイク成功:頭上がすっきりした痛快感。"],
  226. [91..95, "【背後恐怖】\n演出:背後に人が立っているような感覚。\nルーインブレイク成功:後方に憂いのない安心感。"],
  227. [96..100, "【夢中感】\n演出:夢の中にいるような不安な感覚。\nルーインブレイク成功:しっかりとした現実感。"],
  228. # [101, "【任意】\n演出:GMあるいはプレイヤーが演出を行なう。\nルーインブレイク成功:任意"],
  229. ]
  230. ),
  231. "TC" => DiceTable::Table.new(
  232. "トラブルチャート/トラブル解決チャート",
  233. "1D10",
  234. [
  235. "【暴れ馬/交通事故】\nトラブル:いきなり、暴れ馬がやってきて、キミは刎ねられた。\n解決:時間はかかったが、事故は処理された。",
  236. "【突然の崩落/地下遺跡へ移動】\nトラブル:周辺ごと地面が陥没し、地下へと導かれる。\n解決:崩落した先は謎の古代文明の遺跡であった。",
  237. "【暗殺者の襲撃】\nトラブル:凶刃がキャストを襲う。\n解決:何とか暗殺者の手を逃れ、キミは生還した。",
  238. "【拉致・誘拐】\nトラブル:突然、キミは黒覆面の男たちに馬車に押し込まれ、誘拐される。\n解決:何とかして、キミは誘拐組織の手を逃れた。",
  239. "【爆発!!】\nトラブル:爆発した!\n解決:奇跡的にキミは無傷だ、周囲には破壊されたガレキが転がっている。",
  240. "【行きずりの強盗】\nトラブル:訪れていた店やレストラン、銀行などが強盗に襲われる。\n解決:通りすがりのヒーローが強盗を倒した。あれはいったい。",
  241. "【テロリストの襲撃/撃退】\nトラブル:テロリストに襲われる。\n解決:テロリストは撃退された。",
  242. "【交通マヒ/移動変更】\nトラブル:直接、事故に行きあったわけではない事故によって起こった交通マヒによって身動きが取れない。\n解決:交通機関を変更して移動することになった。",
  243. "【軍・警察の封鎖/大捕物】\nトラブル:突如して軍や警察などの治安組織によって建物が封鎖されてしまった。\n解決:建物内にいる犯人を巡り、大捕物が始った。",
  244. "【任意】\nGMと相談してトラブルの内容を決めよう。",
  245. ]
  246. ),
  247. "DA" => DiceTable::Table.new(
  248. "ドタバタアクション表",
  249. "1D10",
  250. [
  251. "【フードファイト(野菜)】大根ソードで切りつけ、カボチャハンマーで殴り抜け",
  252. "【ホコリの雲】ドカッ、バキ、ボカッ。キュウ。",
  253. "【リビングルームストーム】飛び交うソーサー、ポットの中には煎れたばかりの紅茶(抽出温度28度)が入っているぞ。",
  254. "【廊下でランナウェイ】廊下を走っては行けません。",
  255. "【図書館バトル】敏腕司書が、図書館の静寂を乱す者を残らず静かにさせていく。",
  256. "【パーティーファイト】優雅に踊り、紳士淑女の助けを借りて悪漢を退治しよう。",
  257. "【フードファイト(肉と骨)】ヒトに眠る野性を解き放て。羊の骨が最古の武器として再発見される。",
  258. "【イスと机】イスは盾であり、武器であり悪漢をけん制し、拘束する。",
  259. "【洗濯物ファイト】シーツで敵の動きを止めて、石鹸で転ばせよう。",
  260. "【任意】GMと相談して、イメージをふくらませよう。",
  261. ]
  262. ),
  263. }.freeze
  264. 1 register_prefix('RB', 'FP[DR]', TABLES.keys)
  265. end
  266. end
  267. end

lib/bcdice/game_system/RuneQuest.rb

100.0% lines covered

100.0% branches covered

22 relevant lines. 22 lines covered and 0 lines missed.
14 total branches, 14 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class RuneQuest < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'RuneQuest'
  7. # ゲームシステム名
  8. 1 NAME = 'ルーンクエスト'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'るうんくえすと'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. クリティカル、エフェクティブ(効果的成功)、ファンブルの自動判定を行います。
  14. INFO_MESSAGE_TEXT
  15. # ゲーム別成功度判定(1d100)
  16. 1 def result_1d100(total, _dice_total, cmp_op, target)
  17. 43 then: 1 else: 42 return Result.nothing if target == '?'
  18. 42 else: 40 then: 2 return nil unless cmp_op == :<=
  19. # RuneQuest QUICK-START RULESを元に修正
  20. # https://www.chaosium.com/content/FreePDFs/RuneQuest/CHA4027%20-%20RuneQuest%20Quickstart.pdf
  21. 40 critical_value = (target.to_f / 20).round
  22. 40 if (total <= 1) || (total <= critical_value)
  23. then: 2 # 1は常に決定的成功
  24. 2 else: 38 Result.critical("決定的成功")
  25. 38 elsif total >= 100
  26. then: 2 # 100は常に致命的失敗
  27. 2 else: 36 Result.fumble("致命的失敗")
  28. 36 then: 4 elsif total <= (target.to_f / 5).round
  29. 4 else: 32 Result.success("効果的成功")
  30. 32 then: 14 elsif total <= target
  31. 14 else: 18 Result.success("成功")
  32. 18 then: 1 elsif total >= 95 + critical_value
  33. 1 Result.fumble("致命的失敗")
  34. else: 17 else
  35. 17 Result.failure("失敗")
  36. end
  37. end
  38. end
  39. end
  40. end

lib/bcdice/game_system/RuneQuestRoleplayingInGlorantha.rb

90.67% lines covered

80.0% branches covered

75 relevant lines. 68 lines covered and 7 lines missed.
40 total branches, 32 branches covered and 8 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class RuneQuestRoleplayingInGlorantha < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'RuneQuestRoleplayingInGlorantha'
  7. # ゲームシステム名
  8. 1 NAME = 'ルーンクエスト:ロールプレイング・イン・グローランサ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'るうんくえすと4'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定コマンド 決定的成功、効果的成功、ファンブルを含めた判定を行う。
  14. RQG<=成功率 (基本書式)
  15. RQG成功率 (省略記法)
  16. 例1:RQG<=80 (技能値80で判定)
  17. 例2:RQG<=80+20 (技能値100で判定)
  18. 例3:RQG80 (省略書式で技能値80の判定)
  19. 例4:RQG80+20 (省略書式で技能値100の判定)
  20. ・抵抗判定コマンド(能動-受動) 決定的成功、効果的成功、ファンブルを含めた判定を行う。
  21. RES(能動能力-受動能力)m増強値
  22. 増強値は省略可能。
  23. 例1:RES(9-11) (能動能力9 vs 受動能力11で判定)
  24. 例2:RES(9-11)m20 (能動能力9 vs 受動能力11、+20%の増強が能動側に入る判定)
  25. 例3:RES(9)m50 (能動能力と受動能力の差が9で、+50%の増強が能動側に入る判定)
  26. ・抵抗判定コマンド(能動側のみ) 決定的成功、効果的成功、ファンブルは含めず判定を行う。
  27. RSA(能動能力)m増強値
  28. 増強値は省略可能。
  29. 例1:RSA(9) (能動能力9で判定)
  30. 例2:RSA(9)m20 (能動能力9で判定、+20%の増強が能動側に入る判定)
  31. MESSAGETEXT
  32. 1 register_prefix('RQG', 'RES', 'RSA')
  33. 1 def eval_game_system_specific_command(command)
  34. 159 else: 0 case command
  35. when: 78 when /RQG/i
  36. 78 return do_ability_roll(command)
  37. when: 52 when /RES/i
  38. 52 return do_resistance_roll(command)
  39. when: 29 when /RSA/i
  40. 29 return do_resistance_active_characteristic_roll(command)
  41. end
  42. return nil
  43. end
  44. 1 private
  45. # 技能などの一般判定
  46. 1 def do_ability_roll(command)
  47. 78 m = %r{\A(RQG)((<=)?([+-/*\d]+))?$}.match(command)
  48. 78 else: 78 then: 0 unless m
  49. return nil
  50. end
  51. 78 roll_value = @randomizer.roll_once(100)
  52. 78 else: 76 unless m[4]
  53. then: 2 # RQGのみ指定された場合は1d100を振ったのと同じ挙動
  54. 2 return "(1D100) > #{roll_value}"
  55. end
  56. 76 ability_value = Arithmetic.eval(m[4], RoundType::ROUND)
  57. 76 result_prefix_str = "(1D100<=#{ability_value}) >"
  58. 76 else: 72 if ability_value == 0
  59. then: 4 # 0%は判定なしで失敗
  60. 4 return Result.failure("#{result_prefix_str} 失敗")
  61. end
  62. 72 result_str = "#{result_prefix_str} #{roll_value} >"
  63. # 判定
  64. 72 get_roll_result(result_str, ability_value, roll_value)
  65. end
  66. # 抵抗判定
  67. 1 def do_resistance_roll(command)
  68. 52 m = %r{\A(RES)([+-/*\d]+)(M([+-/*\d]+))?$}.match(command)
  69. 52 else: 52 then: 0 unless m
  70. return nil
  71. end
  72. 52 else: 52 then: 0 unless m[2]
  73. return nil
  74. end
  75. 52 difference_value = Arithmetic.eval(m[2], RoundType::ROUND)
  76. 52 then: 2 else: 50 difference_value = -10 if difference_value < -10
  77. 52 resistance_velue = 50 + (difference_value * 5)
  78. 52 then: 8 else: 44 resistance_velue += Arithmetic.eval(m[4], RoundType::ROUND) if m[4]
  79. 52 roll_value = @randomizer.roll_once(100)
  80. 52 result_str = "(1D100<=#{resistance_velue}) > #{roll_value} >"
  81. # 判定
  82. 52 get_roll_result(result_str, resistance_velue, roll_value)
  83. end
  84. # 能動側のみの対抗判定
  85. 1 def do_resistance_active_characteristic_roll(command)
  86. 29 m = %r{\A(RSA)(\d+)(M([+-/*\d]+))?$}.match(command)
  87. 29 else: 29 then: 0 unless m
  88. return nil
  89. end
  90. 29 else: 29 then: 0 unless m[2]
  91. return nil
  92. end
  93. 29 active_ability_value = m[2].to_i
  94. 29 then: 1 else: 28 if active_ability_value == 0
  95. 1 return "0は指定できません。"
  96. end
  97. 28 then: 0 else: 28 modifiy_value = m[4] ? Arithmetic.eval(m[4], RoundType::ROUND) : 0
  98. 28 roll_value = @randomizer.roll_once(100)
  99. 28 active_value = active_ability_value * 5 + modifiy_value
  100. 28 result_prefix_str = "(1D100<=#{active_value}) > #{roll_value} >"
  101. 28 note_str = "決定的成功、効果的成功、ファンブルは未処理。必要なら確認すること。"
  102. 28 if roll_value >= 96
  103. then: 5 # 96以上は無条件で失敗
  104. 5 else: 23 Result.failure("#{result_prefix_str} 失敗\n#{note_str}")
  105. 23 elsif roll_value <= 5 || roll_value <= modifiy_value
  106. then: 5 # 05以下あるいは修正値以下は無条件で成功
  107. 5 Result.success("#{result_prefix_str} 成功\n#{note_str}")
  108. else
  109. else: 18 # 上記全てが当てはまらない時に突破可能な能力値を算出
  110. 18 "#{result_prefix_str} 相手側能力値#{active_ability_value + (50 + modifiy_value - roll_value) / 5}まで成功\n#{note_str}"
  111. end
  112. end
  113. # 判定結果の取得
  114. 1 def get_roll_result(result_str, success_value, roll_value)
  115. 124 critical_value = (success_value.to_f / 20).round
  116. 124 special_value = (success_value.to_f / 5).round
  117. 124 funmble_value = ((100 - success_value.to_f) / 20).round
  118. 124 if (roll_value == 1) || (roll_value <= critical_value)
  119. then: 14 # 決定的成功(01は必ず決定的成功)
  120. 14 else: 110 Result.critical("#{result_str} 決定的成功")
  121. 110 elsif (roll_value == 100) || (roll_value >= (100 - funmble_value + 1))
  122. then: 10 # ファンブル(00は必ずファンブル)
  123. 10 else: 100 Result.fumble("#{result_str} ファンブル")
  124. 100 elsif roll_value >= 96 || ((roll_value > success_value) && (roll_value > 5))
  125. then: 31 # 失敗(96以上は必ず失敗、出目が01-05ではなく技能値より上なら失敗)
  126. 31 else: 69 Result.failure("#{result_str} 失敗")
  127. 69 elsif roll_value <= special_value
  128. then: 17 # 効果的成功
  129. 17 else: 52 Result.success("#{result_str} 効果的成功")
  130. 52 elsif (roll_value <= 5) || (roll_value <= success_value)
  131. then: 52 # 成功(05以下は必ず成功)
  132. 52 Result.success("#{result_str} 成功")
  133. else
  134. else: 0 # ここには到達しないはずだが、念のため捕捉
  135. Result.failure("#{result_str} エラー")
  136. end
  137. end
  138. end
  139. end
  140. end

lib/bcdice/game_system/RyuTuber.rb

94.12% lines covered

75.0% branches covered

17 relevant lines. 16 lines covered and 1 lines missed.
4 total branches, 3 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/dice_table/table"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class RyuTuber < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'RyuTuber'
  8. # ゲームシステム名
  9. 1 NAME = 'リューチューバーとちいさな奇跡'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'りゆうちゆうはあとちいさなきせき'
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ◆判定
  14.  ・判定 nB6<=1
  15.   ※ n:サイコロの数 例)12B6<=1 サイコロの数12個の場合
  16.  ・判定ルールを表示する RTB
  17. ◆職業 (カッコ内は使えそうな技能)
  18.  ・職業表 JT
  19.  ・学生表 JST
  20.  ・技術・専門職表 JTPT
  21.  ・事務・サービス職表 JOST
  22.  ・エンタメ職表 JET
  23. ◆趣味 (カッコ内は使えそうな技能)
  24.  ・趣味表 HT
  25.  ・多人数でできる趣味表 HGT
  26.  ・一人でできるインドア趣味表A HIAT
  27.  ・一人でできるインドア趣味表B HIBT
  28.  ・一人でできるアウトドア趣味表A HOAT
  29.  ・一人でできるアウトドア趣味表B HOBT
  30. ◆奇跡の演目を表示する
  31.  ・幸運の風が吹いている MPW
  32.  ・困った時はお互い様 MPT
  33.  ・悪い予感は的中する MPF
  34.  ・ついていい嘘もある MPL
  35.  ・私には星が見えている MPS
  36.  ・心は竜と共にあり MPD
  37.  ・人は石垣、人は城 MPH
  38. MESSAGETEXT
  39. 1 def eval_game_system_specific_command(command) # ダイスロールコマンド
  40. 19 then: 11 else: 8 if (ret = roll_tables(command, TABLES))
  41. 11 return ret
  42. end
  43. 8 then: 8 else: 0 if (text = TEXTS[command])
  44. 8 return text.chomp
  45. end
  46. return nil
  47. end
  48. 1 TEXTS = {
  49. 'RTB' => <<~TEXT,
  50. 判定ルール表示
  51. ①枠主が判定内容を宣言、判定参加者が行動宣言
  52. ②サイコロは竜の巫女なら6個、技能レベルか指定魅力の値個、奇跡の演目を1つ以上クリアで+6個、スパの消費数個
  53. ③振ったサイコロの「1の目」の数が目標値以上なら華麗に成功、目標値未満ならちょっと残念な結果
  54. TEXT
  55. 'MPW' => <<~TEXT,
  56. 幸運の風が吹いている
  57. 奇跡 以降ゲーム終了まで、サイコロ+1
  58. ①健気に頑張る姿を見せる。
  59. ②報われることはなく、さらに最悪の展開に。
  60. ③それでも健気なところを見せる。
  61. TEXT
  62. 'MPT' => <<~TEXT,
  63. 困った時はお互い様
  64. 奇跡 そのプレイヤーの判定サイコロを1回振り直しできる
  65. ①けちな様子を見せる。
  66. ②困っている人に施しをする姿を見られる。
  67. ③窮地に陥る。
  68. TEXT
  69. 'MPF' => <<~TEXT,
  70. 悪い予感は的中する
  71. 奇跡 1判定だけ、サイコロ+3
  72. ①犠牲者が悪い噂を耳にする。
  73. ②犠牲者が悪い冗談を言う。
  74. ③犠牲者が悪い予感に心さざめき、誰かに悪い予感を話す。
  75. TEXT
  76. 'MPL' => <<~TEXT,
  77. ついていい嘘もある
  78. 奇跡 ついた(ささやかな)嘘が本当になる 枠主判断でいつか発動する。
  79. ①嘘を言う。
  80. ②嘘によって窮地に立つ。
  81. ③嘘を嘘にしないためにあがく。
  82. TEXT
  83. 'MPS' => <<~TEXT,
  84. 私には星が見えている
  85. 奇跡 指定したキャラクターの次の行動がわかる
  86. ①少し先のことを言い当てる。
  87. ②気味が悪いと噂になる。
  88. ③言い当てる力を人間観察に用いる。
  89. TEXT
  90. 'MPD' => <<~TEXT,
  91. 心は竜と共にあり
  92. 奇跡 起こりうる不幸を阻止する
  93. ①心清いひとに助けられる。
  94. ②自分の性根悪さを悲しむ。
  95. ③自分なりのやり方で心清い行いをする。
  96. TEXT
  97. 'MPH' => <<~TEXT,
  98. 人は石垣、人は城
  99. 奇跡 感化された周りの人が手伝うようになる
  100. ①人々の不幸を見て、親切にしてしまう。
  101. ②けなげに頑張る姿を見られる。
  102. ③見ていた人々が集まってくる。
  103. TEXT
  104. }.freeze
  105. TABLES = {
  106. 1 "JT" => DiceTable::Table.new(
  107. "職業表",
  108. "1D6",
  109. [
  110. '学生表へ',
  111. '技術・専門職表へ',
  112. '技術・専門職表へ',
  113. '事務・サービス職表へ',
  114. '事務・サービス職表へ',
  115. 'エンタメ職表へ'
  116. ]
  117. ),
  118. "JST" => DiceTable::Table.new(
  119. "学生表",
  120. "1D6",
  121. [
  122. '中学生 (ゲーム 運動する)',
  123. '高校生(文系) (仲良くする 文章を書く)',
  124. '高校生(理系) (仲良くする 科学の知識)',
  125. '専門学校生 (ものづくり 設計する)',
  126. '大学生(文系) (社会の仕組み 外国語)',
  127. '大学生(理系) (すごい技術 科学の知識)'
  128. ]
  129. ),
  130. "JTPT" => DiceTable::Table.new(
  131. "技術・専門職表",
  132. "2D6",
  133. [
  134. '勝負師・山師 (洞察力 精神力)',
  135. '漁師/猟師 (自然の知識 料理する)',
  136. '建築家、大工 (設計する 運転する)',
  137. '料理人 (料理する ものづくり)',
  138. '職人 (ものづくり 丁寧)',
  139. '農家 (自然の知識 育てる)',
  140. '医療・福祉関係(医師、薬剤師、介護職) (治す 科学の知識)',
  141. '美容、スタイリスト (見た目を整える 仲良くする)',
  142. 'プログラマー (プログラム 設計する)',
  143. '士業(税理士、弁護士、行政書士等) (社会の仕組み 事務仕事)',
  144. '研究者 (教える すごい技術)'
  145. ]
  146. ),
  147. "JOST" => DiceTable::Table.new(
  148. "事務・サービス職表",
  149. "2D6",
  150. [
  151. '宗教関係(巫女、僧侶など) (お祈りする 地元知識)',
  152. '観光、旅行 (外国語 地元知識)',
  153. '教師、保育士 (教える 育てる)',
  154. '運転手、配達員 (運転する 地元知識)',
  155. '自宅警備員 (ゲーム 想像力)',
  156. 'サラリーマン (事務仕事 仲良くする)',
  157. '店員 (丁寧 商品知識)',
  158. '公務員 (事務仕事 地元知識)',
  159. '警察、自衛隊、消防士 (社会の仕組み 戦う)',
  160. '投資家、金融業、不動産 (プレゼンする 事務仕事)',
  161. '経営者 (社会の仕組み 仲良くする)'
  162. ]
  163. ),
  164. "JET" => DiceTable::Table.new(
  165. "エンタメ職表",
  166. "2D6",
  167. [
  168. 'ゲーム制作 (プログラム ものづくり)',
  169. '写真家 (自然の知識 絵を描く)',
  170. 'デザイナー (設計する 見た目を整える)',
  171. 'ライター (文章を書く 想像力)',
  172. 'イラストレーター (絵を描く 見た目を整える)',
  173. '専業配信者 (プレゼンする カリスマ)',
  174. '声優 (声を出す 演技する)',
  175. 'ミュージシャン (声を出す 音楽)',
  176. 'アイドル・芸能人 (演技する カリスマ)',
  177. 'プロゲーマー (ゲーム 戦う)',
  178. 'プロスポーツ選手 (運動する 精神力)'
  179. ]
  180. ),
  181. "HT" => DiceTable::Table.new(
  182. "趣味表",
  183. "1D6",
  184. [
  185. '多人数でできる趣味表へ',
  186. '多人数でできる趣味表へ',
  187. '一人でできるインドア趣味表Aへ',
  188. '一人でできるインドア趣味表Bへ',
  189. '一人でできるアウトドア趣味表Aへ',
  190. '一人でできるアウトドア趣味表Bへ'
  191. ]
  192. ),
  193. "HGT" => DiceTable::Table.new(
  194. "多人数でできる趣味表",
  195. "1D6",
  196. [
  197. '家族サービス (仲良くする 育てる)',
  198. '野球・フットサル (仲良くする 運動する)',
  199. 'ボードゲーム/TRPG/囲碁/将棋 (ゲーム 想像する)',
  200. 'ボランティア (忍耐力 カリスマ)',
  201. 'サバイバルゲーム (戦う 隠れる)',
  202. 'バンド (音楽 見た目を整える)'
  203. ]
  204. ),
  205. "HIAT" => DiceTable::Table.new(
  206. "一人でできるインドア趣味表A",
  207. "1D6",
  208. [
  209. '工芸 (ものづくり 想像力)',
  210. '編み物 (丁寧 見た目を整える)',
  211. '陶芸 (ものづくり 想像力)',
  212. 'プラモ (ものづくり 見た目を整える)',
  213. '同人 (絵を描く 文章を書く)',
  214. '読書 (外国語 社会の仕組み)'
  215. ]
  216. ),
  217. "HIBT" => DiceTable::Table.new(
  218. "一人でできるインドア趣味表B",
  219. "1D6",
  220. [
  221. '仕事 (事務仕事 忍耐力)',
  222. '資格集め (社会の仕組み 商品知識)',
  223. 'お絵かき (絵を描く 想像力)',
  224. '料理 (料理する 設計する)',
  225. '筋トレ (運動する 忍耐力)',
  226. 'コンピューターゲーム (ゲーム プログラム)'
  227. ]
  228. ),
  229. "HOAT" => DiceTable::Table.new(
  230. "一人でできるアウトドア趣味表A",
  231. "1D6",
  232. [
  233. 'スポーツ観戦 (忍耐力 お祈りする)',
  234. '水泳 (運動する 泳ぐ)',
  235. '旅行/鉄道 (移動する 外国語)',
  236. '写真 (自然の知識 想像力)',
  237. 'ジグソーパズル (ゲーム 忍耐力)',
  238. 'マラソン (運動する 忍耐力)'
  239. ]
  240. ),
  241. "HOBT" => DiceTable::Table.new(
  242. "一人でできるアウトドア趣味表B",
  243. "1D6",
  244. [
  245. 'スキー・スノーボード (運動する 自然の知識)',
  246. '自転車 (移動する 運動する)',
  247. '盆栽・生花 (丁寧 育てる)',
  248. 'キャンプ (自然の知識 精神力)',
  249. '映画鑑賞 (演技する 想像力)',
  250. '恋愛 (仲良くする 見た目を整える)'
  251. ]
  252. )
  253. }.freeze
  254. 1 register_prefix(TEXTS.keys + TABLES.keys)
  255. end
  256. end
  257. end

lib/bcdice/game_system/Ryutama.rb

96.15% lines covered

93.48% branches covered

104 relevant lines. 100 lines covered and 4 lines missed.
46 total branches, 43 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Ryutama < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Ryutama'
  7. # ゲームシステム名
  8. 1 NAME = 'りゅうたま'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'りゆうたま'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定
  14.  Rx,y>=t(x,y:使用する能力値、t:目標値)
  15.  1ゾロ、クリティカルも含めて判定結果を表示します
  16.  能力値1つでの判定は Rx>=t で行えます
  17. 例)R8,6>=13
  18. INFO_MESSAGE_TEXT
  19. 1 register_prefix('R')
  20. 1 def initialize(command)
  21. 46 super(command)
  22. 46 @validDiceTypes = [20, 12, 10, 8, 6, 4, 2]
  23. end
  24. 1 def eval_game_system_specific_command(command)
  25. 45 debug('eval_game_system_specific_command begin')
  26. 45 else: 45 then: 0 unless command =~ /^R(\d+)(,(\d+))?([+\-\d]+)?(>=(\d+))?/
  27. debug('unmatched!')
  28. return ''
  29. end
  30. 45 debug('matched')
  31. 45 dice1 = Regexp.last_match(1).to_i
  32. 45 dice2 = Regexp.last_match(3).to_i
  33. 45 modifyString = Regexp.last_match(4)
  34. 45 difficulty = Regexp.last_match(6)
  35. 45 dice1, dice2 = getDiceType(dice1, dice2)
  36. 45 then: 1 else: 44 if dice1 == 0
  37. 1 return ''
  38. end
  39. 44 modifyString ||= ''
  40. 44 modify = ArithmeticEvaluator.eval(modifyString)
  41. 44 difficulty = getDiffculty(difficulty)
  42. 44 value1 = getRollValue(dice1)
  43. 44 value2 = getRollValue(dice2)
  44. 44 total = value1 + value2 + modify
  45. 44 result = getResultText(value1, value2, dice1, dice2, difficulty, total)
  46. 44 else: 11 then: 33 unless result.empty?
  47. 33 result = " > #{result}"
  48. end
  49. 44 value1Text = "#{value1}(#{dice1})"
  50. 44 then: 5 else: 39 value2Text = (value2 == 0 ? "" : "+#{value2}(#{dice2})")
  51. 44 modifyText = getModifyString(modify)
  52. 44 baseText = getBaseText(dice1, dice2, modify, difficulty)
  53. 44 output = "(#{baseText}) > #{value1Text}#{value2Text}#{modifyText} > #{total}#{result}"
  54. 44 return output
  55. end
  56. 1 def getDiceType(dice1, dice2)
  57. 45 debug('getDiceType begin')
  58. 45 then: 23 else: 22 if dice2 != 0
  59. 23 then: 23 if isValidDiceOne(dice1)
  60. 23 return dice1, dice2
  61. else: 0 else
  62. return 0, 0
  63. end
  64. end
  65. 22 then: 0 else: 22 if isValidDice(dice1, dice2)
  66. return dice1, dice2
  67. end
  68. 22 diceBase = dice1
  69. 22 dice1 = diceBase / 10
  70. 22 dice2 = diceBase % 10
  71. 22 then: 11 else: 11 if isValidDice(dice1, dice2)
  72. 11 return dice1, dice2
  73. end
  74. 11 dice1 = diceBase / 100
  75. 11 dice2 = diceBase % 100
  76. 11 then: 5 else: 6 if isValidDice(dice1, dice2)
  77. 5 return dice1, dice2
  78. end
  79. 6 then: 5 else: 1 if isValidDiceOne(diceBase)
  80. 5 return diceBase, 0
  81. end
  82. 1 return 0, 0
  83. end
  84. 1 def isValidDice(dice1, dice2)
  85. 55 return isValidDiceOne(dice1) &&
  86. isValidDiceOne(dice2)
  87. end
  88. 1 def isValidDiceOne(dice)
  89. 106 @validDiceTypes.include?(dice)
  90. end
  91. 1 def getDiffculty(difficulty)
  92. 44 else: 13 then: 31 unless difficulty.nil?
  93. 31 difficulty = difficulty.to_i
  94. end
  95. 44 return difficulty
  96. end
  97. 1 def getRollValue(dice)
  98. 88 then: 5 else: 83 return 0 if dice == 0
  99. 83 value = @randomizer.roll_once(dice)
  100. 83 return value
  101. end
  102. 1 def getResultText(value1, value2, dice1, dice2, difficulty, total)
  103. 44 then: 2 else: 42 if isFamble(value1, value2)
  104. 2 return "1ゾロ【1ゾロポイント+1】"
  105. end
  106. 42 then: 11 else: 31 if isCritical(value1, value2, dice1, dice2)
  107. 11 return "クリティカル成功"
  108. end
  109. 31 then: 11 else: 20 if difficulty.nil?
  110. 11 return ''
  111. end
  112. 20 then: 10 else: 10 if total >= difficulty
  113. 10 return "成功"
  114. end
  115. 10 return "失敗"
  116. end
  117. 1 def isFamble(value1, value2)
  118. 44 return (value1 == 1) && (value2 == 1)
  119. end
  120. 1 def isCritical(value1, value2, dice1, dice2)
  121. 42 then: 5 else: 37 return false if value2 == 0
  122. 37 then: 6 else: 31 if (value1 == 6) && (value2 == 6)
  123. 6 return true
  124. end
  125. 31 then: 5 else: 26 if (value1 == dice1) && (value2 == dice2)
  126. 5 return true
  127. end
  128. 26 return false
  129. end
  130. 1 def getBaseText(dice1, dice2, modify, difficulty)
  131. 44 baseText = "R#{dice1}"
  132. 44 then: 39 else: 5 if dice2 != 0
  133. 39 baseText += ",#{dice2}"
  134. end
  135. 44 baseText += getModifyString(modify)
  136. 44 else: 13 then: 31 unless difficulty.nil?
  137. 31 baseText += ">=#{difficulty}"
  138. end
  139. 44 return baseText
  140. end
  141. 1 def getModifyString(modify)
  142. 88 then: 8 if modify > 0
  143. 8 else: 80 return "+" + modify.to_s
  144. 80 then: 8 else: 72 elsif modify < 0
  145. 8 return modify.to_s
  146. end
  147. 72 return ''
  148. end
  149. end
  150. end
  151. end

lib/bcdice/game_system/SRS.rb

96.23% lines covered

89.29% branches covered

106 relevant lines. 102 lines covered and 4 lines missed.
28 total branches, 25 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/arithmetic_evaluator'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class SRS < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'SRS'
  8. # ゲームシステム名
  9. 1 NAME = 'スタンダードRPGシステム'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'すたんたあとRPGしすてむ'
  12. 1 HELP_MESSAGE_1 = <<~HELP_MESSAGE
  13. ・判定
  14.  ・通常判定:2D6+m@c#f>=t または 2D6+m>=t[c,f]
  15.   修正値m、目標値t、クリティカル値c、ファンブル値fで判定ロールを行います。
  16.   修正値、クリティカル値、ファンブル値は省略可能です([]ごと省略可、@c・#fの指定は順不同)。
  17.   クリティカル値、ファンブル値の既定値は、それぞれ12、2です。
  18.   自動成功、自動失敗、成功、失敗を自動表示します。
  19.   例) 2d6>=10     修正値0、目標値10で判定
  20.   例) 2d6+2>=10    修正値+2、目標値10で判定
  21.   例) 2d6+2>=10[11]  ↑をクリティカル値11で判定
  22.   例) 2d6+2@11>=10   ↑をクリティカル値11で判定
  23.   例) 2d6+2>=10[12,4] ↑をクリティカル値12、ファンブル値4で判定
  24.   例) 2d6+2@12#4>=10  ↑をクリティカル値12、ファンブル値4で判定
  25.   例) 2d6+2>=10[,4]  ↑をクリティカル値12、ファンブル値4で判定(クリティカル値の省略)
  26.   例) 2d6+2#4>=10   ↑をクリティカル値12、ファンブル値4で判定(クリティカル値の省略)
  27. HELP_MESSAGE
  28. 1 HELP_MESSAGE_2 = <<~HELP_MESSAGE
  29.  ・クリティカルおよびファンブルのみの判定:2D6+m@c#f または 2D6+m[c,f]
  30.   目標値を指定せず、修正値m、クリティカル値c、ファンブル値fで判定ロールを行います。
  31.   修正値、クリティカル値、ファンブル値は省略可能です([]は省略不可、@c・#fの指定は順不同)。
  32.   自動成功、自動失敗を自動表示します。
  33.   例) 2d6[]    修正値0、クリティカル値12、ファンブル値2で判定
  34.   例) 2d6+2[11]  修正値+2、クリティカル値11、ファンブル値2で判定
  35.   例) 2d6+2@11   修正値+2、クリティカル値11、ファンブル値2で判定
  36.   例) 2d6+2[12,4] 修正値+2、クリティカル値12、ファンブル値4で判定
  37.   例) 2d6+2@12#4  修正値+2、クリティカル値12、ファンブル値4で判定
  38. HELP_MESSAGE
  39. 1 HELP_MESSAGE_3 = <<~HELP_MESSAGE
  40. ・D66ダイスあり(入れ替えなし)
  41. HELP_MESSAGE
  42. # 既定のダイスボット説明文
  43. 1 DEFAULT_HELP_MESSAGE = "#{HELP_MESSAGE_1}\n#{HELP_MESSAGE_2}\n#{HELP_MESSAGE_3}"
  44. 1 HELP_MESSAGE = DEFAULT_HELP_MESSAGE
  45. # 成功判定のエイリアスコマンド定義用のクラスメソッドを提供するモジュール
  46. 1 module ClassMethods
  47. # 成功判定のエイリアスコマンドの一覧
  48. # @return [Array<String>]
  49. 1 attr_reader :aliases
  50. # ダイスボットの説明文を返す
  51. # @return [String]
  52. 1 attr_reader :help_message
  53. # 成功判定のエイリアスコマンドを設定する
  54. # @param [String] aliases エイリアスコマンド(可変長引数)
  55. # @return [self]
  56. #
  57. # エイリアスコマンドとして指定した文字列がコマンドの先頭にあれば、
  58. # 実行時にそれが2D6に置換されるようになる。
  59. 1 def set_aliases_for_srs_roll(*aliases)
  60. 5 aliases_upcase = aliases.map(&:upcase)
  61. 12 @aliases = aliases_upcase.map { |a| Regexp.escape(a) }
  62. 5 @help_message = concatenate_help_messages(aliases_upcase)
  63. 5 return self
  64. end
  65. # 成功判定のエイリアスコマンドを未設定にする
  66. # @return [self]
  67. 1 def clear_aliases_for_srs_roll
  68. 5 @aliases = []
  69. 5 @help_message = SRS::DEFAULT_HELP_MESSAGE
  70. 5 return self
  71. end
  72. 1 private
  73. # ダイスボットの説明文を結合する
  74. # @param [Array<String>] aliases エイリアスコマンドの配列
  75. # @return [String] 結合された説明文
  76. # @todo 現在は2文字のエイリアスコマンドに幅を合わせてある。
  77. # エイリアスコマンドの文字数が変わる場合があれば、位置を調整するコードが
  78. # 必要。
  79. 1 def concatenate_help_messages(aliases)
  80. help_msg_for_aliases_for_target_value =
  81. 5 aliases
  82. .map do |a|
  83. 7 "  例) #{a}+2>=10     2d6+2>=10と同じ(#{a}が2D6のショートカットコマンド)\n"
  84. end
  85. .join()
  86. help_msg_for_aliases_for_without_target_value =
  87. 5 aliases
  88. .map do |a|
  89. 7 "  例) #{a}      2d6[]と同じ(#{a}が2D6のショートカットコマンド)\n" \
  90. "  例) #{a}+2@12#4  2d6+2@12#4と同じ(#{a}が2D6のショートカットコマンド)\n"
  91. end
  92. .join()
  93. 5 return "#{SRS::HELP_MESSAGE_1}" \
  94. "#{help_msg_for_aliases_for_target_value}\n" \
  95. "#{SRS::HELP_MESSAGE_2}" \
  96. "#{help_msg_for_aliases_for_without_target_value}\n" \
  97. "#{SRS::HELP_MESSAGE_3}"
  98. end
  99. end
  100. 1 class << self
  101. # クラスが継承されたときに行う処理
  102. # @return [void]
  103. 1 def inherited(subclass)
  104. 5 subclass
  105. .extend(ClassMethods)
  106. .clear_aliases_for_srs_roll
  107. end
  108. # ダイスボットの説明文を返す
  109. # @return [String] 既定のダイスボット説明文
  110. 1 def help_message
  111. DEFAULT_HELP_MESSAGE
  112. end
  113. # 成功判定のエイリアスコマンドの一覧
  114. # @return [Array<String>]
  115. 1 def aliases
  116. 74 []
  117. end
  118. end
  119. # 固有のコマンドの接頭辞を設定する
  120. 1 register_prefix('2D6')
  121. # ダイスボットを初期化する
  122. 1 def initialize(command)
  123. 204 super(command)
  124. # 式、出目ともに送信する
  125. # バラバラロール(Bコマンド)でソートする
  126. 204 @sort_add_dice = true
  127. # D66ダイスあり(出目をソートしない)
  128. 204 @d66_sort_type = D66SortType::NO_SORT
  129. end
  130. # ダイスボットの説明文を返す
  131. # @return [String]
  132. 1 def help_message
  133. self.class.help_message
  134. end
  135. # 成功判定のエイリアスコマンドの一覧
  136. # @return [Array<String>]
  137. 1 def aliases
  138. 199 self.class.aliases
  139. end
  140. # 既定のクリティカル値
  141. 1 DEFAULT_CRITICAL_VALUE = 12
  142. # 既定のファンブル値
  143. 1 DEFAULT_FUMBLE_VALUE = 2
  144. # 成功判定コマンドのノード
  145. 1 SRSRollNode = Struct.new(
  146. :modifier, :critical_value, :fumble_value, :target_value
  147. ) do
  148. # 成功判定の文字列表記を返す
  149. # @return [String]
  150. 1 def to_s
  151. 173 lhs = "2D6#{Format.modifier(modifier)}"
  152. 173 then: 64 else: 109 expression = target_value ? "#{lhs}>=#{target_value}" : lhs
  153. 173 return "#{expression}[#{critical_value},#{fumble_value}]"
  154. end
  155. end
  156. # 固有のダイスロールコマンドを実行する
  157. # @param [String] command 入力されたコマンド
  158. # @return [Result, nil] ダイスロールコマンドの実行結果
  159. 1 def eval_game_system_specific_command(command)
  160. 199 legacy_c_f_match = /(.+)\[(.*)\]\z/.match(command)
  161. node =
  162. 199 then: 59 if legacy_c_f_match
  163. 59 parse_legacy(legacy_c_f_match[1], legacy_c_f_match[2])
  164. else: 140 else
  165. 140 parse(command)
  166. end
  167. 199 then: 173 else: 26 if node
  168. 173 return execute_srs_roll(node)
  169. end
  170. 26 return nil
  171. end
  172. 1 private
  173. 1 def parse(command)
  174. 140 prefix_re = Regexp.new(["2D6"].concat(aliases()).join('|'), Regexp::IGNORECASE)
  175. 140 parser = Command::Parser.new(prefix_re, round_type: @round_type)
  176. .enable_critical
  177. .enable_fumble
  178. .restrict_cmp_op_to(nil, :>=)
  179. 140 cmd = parser.parse(command)
  180. 140 else: 116 then: 24 unless cmd
  181. 24 return nil
  182. end
  183. 116 else: 114 if command.start_with?(/2D6/i) && cmd.critical.nil? && cmd.fumble.nil? && cmd.target_number.nil?
  184. then: 2 # fallback to default dice
  185. 2 return nil
  186. end
  187. 114 cmd.critical ||= DEFAULT_CRITICAL_VALUE
  188. 114 cmd.fumble ||= DEFAULT_FUMBLE_VALUE
  189. 114 return SRSRollNode.new(cmd.modify_number, cmd.critical, cmd.fumble, cmd.target_number)
  190. end
  191. 1 def parse_legacy(command, c_f)
  192. 59 m = /^(-?\d+)?(?:,(-?\d+))?$/.match(c_f)
  193. 59 else: 59 then: 0 unless m
  194. return nil
  195. end
  196. 59 then: 51 else: 8 critical = m[1]&.to_i || DEFAULT_CRITICAL_VALUE
  197. 59 then: 44 else: 15 fumble = m[2]&.to_i || DEFAULT_FUMBLE_VALUE
  198. 59 prefix_re = Regexp.new(["2D6"].concat(aliases()).join('|'), Regexp::IGNORECASE)
  199. 59 parser = Command::Parser.new(prefix_re, round_type: @round_type)
  200. .restrict_cmp_op_to(nil, :>=)
  201. 59 cmd = parser.parse(command)
  202. 59 else: 59 then: 0 unless cmd
  203. return nil
  204. end
  205. 59 return SRSRollNode.new(cmd.modify_number, critical, fumble, cmd.target_number)
  206. end
  207. # 成功判定を実行する
  208. # @param [SRSRollNode] srs_roll 成功判定ノード
  209. # @return [Result] 成功判定結果
  210. 1 def execute_srs_roll(srs_roll)
  211. 173 dice_list = @randomizer.roll_barabara(2, 6)
  212. 173 then: 173 else: 0 dice_list.sort! if @sort_add_dice
  213. 173 sum = dice_list.sum()
  214. 173 dice_str = dice_list.join(",")
  215. 173 modified_sum = sum + srs_roll.modifier
  216. 173 result = compare_result(srs_roll, sum, modified_sum)
  217. parts = [
  218. 173 "(#{srs_roll})",
  219. "#{sum}[#{dice_str}]#{Format.modifier(srs_roll.modifier)}",
  220. modified_sum,
  221. result.text
  222. ]
  223. 173 result.text = parts.compact.join(' > ')
  224. 173 result
  225. end
  226. # ダイスロール結果を目標値、クリティカル値、ファンブル値と比較する
  227. # @param [SRSRollNode] srs_roll 成功判定ノード
  228. # @param [Integer] sum 出目の合計
  229. # @param [Integer] modified_sum 修正後の値
  230. # @return [Result] 比較結果
  231. 1 def compare_result(srs_roll, sum, modified_sum)
  232. 173 then: 52 if sum >= srs_roll.critical_value
  233. 52 else: 121 Result.critical("自動成功")
  234. 121 then: 38 elsif sum <= srs_roll.fumble_value
  235. 38 else: 83 Result.fumble("自動失敗")
  236. 83 then: 49 elsif srs_roll.target_value.nil?
  237. 49 else: 34 Result.new
  238. 34 then: 16 elsif modified_sum >= srs_roll.target_value
  239. 16 Result.success("成功")
  240. else: 18 else
  241. 18 Result.failure("失敗")
  242. end
  243. end
  244. end
  245. end
  246. end

lib/bcdice/game_system/SajinsenkiAGuS.rb

100.0% lines covered

96.43% branches covered

70 relevant lines. 70 lines covered and 0 lines missed.
28 total branches, 27 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class SajinsenkiAGuS < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'SajinsenkiAGuS'
  7. # ゲームシステム名
  8. 1 NAME = '砂塵戦機アーガス'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'さしんせんきああかす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・一般判定Lv(チャンス出目0→判定0) nAG+x
  14.    nは習得レベル、Lv0の場合nの省略可能。xは判定値修正(数式による修正可)、省略した場合はレベル修正0
  15.    例)AG:習得レベル0の一般技能、1AG+1:習得レベル1・判定値修正+1の技能、AG+2-1:習得レベル0・判定値修正2-1の技能、(1-1)AG:習得レベル1・レベル修正-1の技能
  16. ・適正距離での命中判定(チャンス出目0→判定0、HR算出)OM+y@z
  17.    yは命中補正値(数式可)、zはクリティカル値。クリティカル値省略時は0
  18.    HRの算出時には、HRが大きくなる場合に出目0を10に読み替えます。
  19.    例)OM+18-6@2:命中補正値+18-6でクリティカル値2、適正距離の判定
  20. ・非適正距離での命中判定(チャンス出目0→判定0、HR算出)NM+y@z
  21.    yは命中補正値(数式可)、zはクリティカル値。クリティカル値省略時は0
  22.    HRの算出時には、HRが大きくなる場合に出目0を10に読み替えます。
  23.    例)NM+4-3:命中補正値+4-3で非適正距離の判定
  24. ・クリティカル表 CR
  25. ※通常の1D10などの10面ダイスにおいて出目10の読み替えはしません。コマンドのみです。
  26. INFO_MESSAGE_TEXT
  27. 1 register_prefix('-?\d*AG', 'OM', 'NM', 'CR')
  28. 1 def eval_game_system_specific_command(command)
  29. 75 roll_ippan(command) || roll_hit_check(command) || roll_tables(command, TABLES)
  30. end
  31. 1 private
  32. 1 def roll_ippan(command)
  33. 76 m = /^(-?\d+)?AG((?:[-+]\d+)*)$/.match(command)
  34. 76 else: 22 then: 54 return nil unless m
  35. 22 level = m[1].to_i
  36. 22 x = Arithmetic.eval(m[2], @round_type) || 0
  37. 22 then: 12 else: 10 target = level <= 0 ? 7 + x : 10 + level + x
  38. 66 then: 14 else: 30 dice_list = @randomizer.roll_barabara(2, 10).map { |d| d == 10 ? 0 : d }
  39. 22 total = dice_list.sum
  40. 66 success_level = 1 + dice_list.count { |val| val <= level }
  41. 22 return Result.new.tap do |result|
  42. 22 result.condition = total <= target
  43. 22 result.rands = dice_list
  44. sequence = [
  45. 22 "(2D10<=#{target})",
  46. "#{total}[#{dice_list.join(',')}]",
  47. 22 then: 14 else: 8 ("チャンス" if dice_list.include?(0)),
  48. 22 then: 12 else: 10 result.success? ? "成功(+#{success_level})" : "失敗"
  49. ].compact
  50. 22 result.text = sequence.join(" > ")
  51. end
  52. end
  53. # 命中判定&HR算出
  54. 1 def roll_hit_check(command)
  55. 56 parser = Command::Parser.new("OM", "NM", round_type: @round_type).enable_critical
  56. 56 parsed = parser.parse(command)
  57. 56 else: 28 then: 28 return nil unless parsed
  58. 28 then: 16 if parsed.command == "OM"
  59. 16 else: 12 return roll_om(parsed)
  60. 12 then: 12 else: 0 elsif parsed.command == "NM"
  61. 12 return roll_nm(parsed)
  62. end
  63. end
  64. 1 def roll_om(parsed)
  65. 16 target = parsed.modify_number
  66. 16 critical = parsed.critical || 0
  67. 48 then: 8 else: 24 dice_list = @randomizer.roll_barabara(2, 10).map { |v| v == 10 ? 0 : v }.sort.reverse
  68. 16 total = dice_list.sum()
  69. 48 criticals = dice_list.count { |v| v <= critical }
  70. 16 hr = calc_hr(target, dice_list)
  71. 16 return Result.new.tap do |r|
  72. 16 r.condition = total <= target
  73. 16 r.rands = dice_list
  74. 16 r.critical = criticals >= 1
  75. 16 r.text = [
  76. "(2D10<=#{target})",
  77. "#{total}[#{dice_list.join(',')}]",
  78. 16 then: 8 else: 8 ("チャンス" if dice_list.include?(0)),
  79. 16 then: 14 else: 2 r.success? ? "成功(HR=#{hr}、クリティカル#{criticals})" : "失敗",
  80. ].compact.join(" > ")
  81. end
  82. end
  83. 1 def roll_nm(parsed)
  84. 12 target = parsed.modify_number
  85. 12 critical = parsed.critical || 0
  86. 48 then: 10 else: 26 dice_list = @randomizer.roll_barabara(3, 10).map { |v| v == 10 ? 0 : v }.sort.reverse
  87. 12 chosen_dice_list = dice_list.take(2)
  88. 12 total = chosen_dice_list.sum()
  89. 36 criticals = chosen_dice_list.count { |v| v <= critical }
  90. 12 hr = calc_hr(target, chosen_dice_list)
  91. 12 return Result.new.tap do |r|
  92. 12 r.condition = total <= target
  93. 12 r.rands = dice_list
  94. 12 r.critical = criticals >= 1
  95. 12 r.text = [
  96. "(3D10<=#{target})",
  97. "#{total}[#{dice_list[0]},#{dice_list[1]}&#{dice_list[2]}]",
  98. 12 then: 4 else: 8 ("チャンス" if chosen_dice_list.include?(0)),
  99. 12 then: 8 else: 4 r.success? ? "成功(HR=#{hr}、クリティカル#{criticals})" : "失敗",
  100. ].compact.join(" > ")
  101. end
  102. end
  103. 1 def calc_hr(target, chosen_dice_list)
  104. 28 total = chosen_dice_list.sum()
  105. 28 a = (target - total).abs
  106. 28 b = (target - total - chosen_dice_list.count(0) * 10).abs
  107. 28 return [a, b].max
  108. end
  109. TABLES = {
  110. 1 "CR" => DiceTable::Table.new(
  111. "クリティカル表",
  112. "1D10",
  113. [
  114. "1:「小破」ダメージ+[5]。耐久値-[1]",
  115. "2:「小破」ダメージ+[5]。耐久値-[1]",
  116. "3:「小破」ダメージ+[5]。耐久値-[1]",
  117. "4:「小破」ダメージ+[5]。耐久値-[1]",
  118. "5:「兵装」損壊を受けるごとに[1D10]を振り、出目に応じた部位の兵装とオプションが《脱落》",
  119. "6:「上体」攻撃系能力[白兵/ 火器/ 索敵]は各[- 損壊Lv]",
  120. "7:「脚部」行動系・防御系能力[Iv 値(イニシア値)/ 最大MP/ 回避]は各[- 損壊Lv]",
  121. "8:「搭乗者」搭乗者の〈最大HP〉および〈HP〉は[-(4 ×損壊Lv)]",
  122. "9:「搭乗者」搭乗者の〈最大HP〉および〈HP〉は[-(4 ×損壊Lv)]",
  123. "0:「小破」ダメージ+[5]。耐久値-[1]",
  124. ]
  125. )
  126. }.freeze
  127. end
  128. end
  129. end

lib/bcdice/game_system/SajinsenkiAGuS2E.rb

100.0% lines covered

75.0% branches covered

35 relevant lines. 35 lines covered and 0 lines missed.
8 total branches, 6 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/SajinsenkiAGuS'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class SajinsenkiAGuS2E < SajinsenkiAGuS
  6. # ゲームシステムの識別子
  7. 1 ID = 'SajinsenkiAGuS2E'
  8. # ゲームシステム名
  9. 1 NAME = '砂塵戦機アーガス2ndEdition'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'さしんせんきああかす2'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・一般判定Lv(チャンス出目0→判定0) nAG+x
  15.    nは習得レベル、Lv0の場合nの省略可能。xは判定値修正(数式による修正可)、省略した場合はレベル修正0
  16.    例)AG:習得レベル0の一般技能、1AG+1:習得レベル1・判定値修正+1の技能、AG+2-1:習得レベル0・判定値修正2-1の技能、(1-1)AG:習得レベル1・レベル修正-1の技能
  17. ・適正距離での命中判定(チャンス出目0→判定0、HR算出)OM+y@z
  18.    yは命中補正値(数式可)、zはクリティカル値。クリティカル値省略時は0
  19.    HRの算出時には、HRが大きくなる場合に出目0を10に読み替えます。
  20.    例)OM+18-6@2:命中補正値+18-6でクリティカル値2、適正距離の判定
  21. ・非適正距離での命中判定(チャンス出目0→判定0、HR算出)NM+y@z
  22.    yは命中補正値(数式可)、zはクリティカル値。クリティカル値省略時は0
  23.    HRの算出時には、HRが大きくなる場合に出目0を10に読み替えます。
  24.    例)NM+4-3:命中補正値+4-3で非適正距離の判定
  25. ・『西風旅徨』で導入されたファンブル・ルールを用いた判定
  26.  判定時にダイスがすべて8以上ならファンブル(自動失敗)です。
  27.  それぞれのコマンドにWを付けると『西風旅徨』モードになります。
  28.    ・一般判定 nAGW+x
  29.    ・適正距離での命中判定 OMW+y@z
  30.    ・非適正距離での命中判定 NMW+y@z
  31. ・クリティカル表   CR
  32. ・鹵獲結果表     CAP
  33. ・幕間クエスト表   INT
  34. ・サルベージ表    SAL
  35. ・赤字ペナルティー表 DEF
  36. ・特殊戦況表     SPE
  37. ※通常の1D10などの10面ダイスにおいて出目10の読み替えはしません。コマンドのみです。
  38.  ページ参照は、何もない場合は「ルールブック」、wは「西風旅徨」を示します。
  39. INFO_MESSAGE_TEXT
  40. 1 def initialize(command)
  41. 49 super(command)
  42. 49 @enabled_d9 = true
  43. end
  44. 1 def eval_game_system_specific_command(command)
  45. 49 super(command) ||
  46. roll_ippan_west(command) ||
  47. roll_hit_check_west(command) ||
  48. roll_tables(command, SECOND_ED_TABLES)
  49. end
  50. 1 def roll_ippan_west(command)
  51. 20 m = /AGW/.match(command)
  52. 20 else: 1 then: 19 return nil unless m
  53. 2 result = roll_ippan(command.sub(/(AG)W/) { ::Regexp.last_match(1) })
  54. 1 return change_fumble(result)
  55. end
  56. 1 def roll_hit_check_west(command)
  57. 19 m = /[ON]MW/.match(command)
  58. 19 else: 2 then: 17 return nil unless m
  59. 4 result = roll_hit_check(command.sub(/([ON]M)W/) { ::Regexp.last_match(1) })
  60. 2 return change_fumble(result)
  61. end
  62. 1 def change_fumble(result)
  63. 3 then: 0 else: 3 return nil if result.nil?
  64. 10 fumble_counts = result.rands.count { |val| val >= 8 }
  65. 3 then: 3 else: 0 if fumble_counts >= 2
  66. 3 result.text = result.text.sub(/(成功|失敗).*$/, 'ファンブル')
  67. 3 result.failure = true
  68. 3 result.success = false
  69. 3 result.fumble = true
  70. end
  71. 3 return result
  72. end
  73. SECOND_ED_TABLES = {
  74. 1 "CAP" => DiceTable::Table.new(
  75. "鹵獲結果表",
  76. "2D10",
  77. [
  78. '0:敵A:GuS を完全な状態で鹵獲︕ ※総合価格÷ 2 で売却可。',
  79. '1:敵A:GuS を完全な状態で鹵獲︕ ※総合価格÷ 2 で売却可。',
  80. '2:敵A:GuS を完全な状態で鹵獲︕ ※総合価格÷ 2 で売却可。',
  81. '3:敵A:GuS の兵装を鹵獲︕ ※敵A:GuS の装備している任意の兵装1つを獲得。',
  82. '4:敵A:GuS の兵装を鹵獲︕ ※敵A:GuS の装備している任意の兵装1つを獲得。',
  83. '5:敵A:GuS の兵装を鹵獲︕ ※敵A:GuS の装備している任意の兵装1つを獲得。',
  84. '6:敵A:GuS の兵装を鹵獲︕ ※敵A:GuS の装備している任意の兵装1つを獲得。',
  85. '7:敵A:GuS の兵装を鹵獲︕ ※敵A:GuS の装備している任意の兵装1つを獲得。',
  86. '8:使えそうな兵装を発見︕ ※1D10 を振り、出目の部位の兵装1つを獲得。',
  87. '9:使えそうな兵装を発見︕ ※1D10 を振り、出目の部位の兵装1つを獲得。',
  88. '10:使えそうな兵装を発見︕ ※1D10 を振り、出目の部位の兵装1つを獲得。',
  89. '11:使えそうな兵装を発見︕ ※1D10 を振り、出目の部位の兵装1つを獲得。',
  90. '12:使えそうな兵装を発見︕ ※1D10 を振り、出目の部位の兵装1つを獲得。',
  91. '13:使えそうな兵装を発見︕ ※1D10 を振り、出目の部位の兵装1つを獲得。',
  92. '14:残念、完全にスクラップだ……。※部品代として[バランス値×300]cdtを獲得。',
  93. '15:残念、完全にスクラップだ……。※部品代として[バランス値×300]cdtを獲得。',
  94. '16:残念、完全にスクラップだ……。※部品代として[バランス値×300]cdtを獲得。',
  95. '17:残念、完全にスクラップだ……。※部品代として[バランス値×300]cdtを獲得。',
  96. '18:残念、完全にスクラップだ……。※部品代として[バランス値×300]cdtを獲得。',
  97. ]
  98. ),
  99. "INT" => DiceTable::RangeTable.new(
  100. "幕間クエスト表",
  101. "1D100",
  102. [
  103. [1, '慰労 PC/クルー1名が、労ってくれる。 最大HP+4'],
  104. [2..3, '感謝 PC/クルー1名が、感謝の気持ちを伝える。 最大HP+4'],
  105. [4..5, '安堵 PC/ クルー1名が、安堵の気持ちを伝える。 最大HP+4'],
  106. [6..7, '治療 戦闘中の怪我や急な病気で医療班のお世話になることに。 最大HP+4'],
  107. [8..9, '日常 PC/クルー1名と、他愛のない日常の会話をする。 最大HP+4'],
  108. [10..11, '遊興 PC/クルー1名と遊びに興じ、楽しい時を過ごす。 XP+1'],
  109. [12..13, '勤労 PC/クルー1名と協力し、船内の仕事を行う。 XP+1'],
  110. [14..15, '評価 PC/クルー1名が、仕事の出来を評価してくれる。 XP+1'],
  111. [16..17, '調達 PC/クルー1名とともに生活品の買い出しを行うことに。 XP+1'],
  112. [18..19, '社交 取引や補給などの仕事を通し、船外での社会経験を得る。 XP+1'],
  113. [20..21, '注意 PC/クルー1名が、君の危険な戦闘行動について指摘する。 SP+1'],
  114. [22..23, '反省 PC/クルー1名と、作戦行動の反省会を行う。 SP+1'],
  115. [24..25, '鍛錬 PC/クルー1名に、模擬戦に付き合ってもらう。 SP+1'],
  116. [26..27, '感心 PC/クルー1名の仕事や戦闘行動に対し、感銘を受ける。 SP+1'],
  117. [28..29, '改良 整備班と協力し、A:GuSのプログラムの改良に努める。 SP+1'],
  118. [30..31, '割引 兵装が割引されているのを発見し、格安で購入できる。 基本兵装1つを半額で購入可。'],
  119. [32..33, '発見 クルー1名が、兵装を入手した。 基本兵装1つを半額で購入可。'],
  120. [34..35, '発明 クルー1名が、兵装を開発した。 基本兵装1つを半額で購入可。'],
  121. [36..37, '大発見 クルー1名が、強力な兵装を入手した! 上級兵装1つを購入可。(p37参照)'],
  122. [38..39, '大発明 クルー1名が、新たな兵装を開発した! 上級兵装1つを購入可。(p37参照)'],
  123. [40..41, '昔話 PC/クルー1名に、自分の過去について語ってしまう。 最大LP+1'],
  124. [42..43, '願望 PC/クルー1名に、自分の夢や未来について語ってしまう。 最大LP+1'],
  125. [44..45, '家族 PC/クルー1名に、自分の家族について語ってしまう。 最大LP+1'],
  126. [46..47, '望郷 PC/クルー1名に、自分の故郷について語ってしまう。 最大LP+1'],
  127. [48..49, '知人 PC/クルー1名に、自分の知人を重ね合わせてしまう。 最大LP+1'],
  128. [50..51, '個人収入 チームとは関係ない個人的な商売や取引で利益を得る。 4,000cdtを獲得。'],
  129. [52..53, '臨時収入 思いがけない臨時の収入が入る。 4,000cdt を獲得。'],
  130. [54..55, '取引 クルー1 名と取引を行い、予算を獲得することに成功する。 4,000cdtを獲得。'],
  131. [56..57, '裏取引 クルー1 名と秘密の取引を行い、見返りとして予算を獲得。 6,000cdtを獲得。'],
  132. [58..59, '賞与 オーナーが特別に報酬を用意してくれた! 6,000cdtを獲得。'],
  133. [60..61, '改造 整備班とともに機体の改造に明け暮れる。 任意の改造Lv+1。(上限:2Lv)'],
  134. [62..63, '鹵獲 鹵獲品の中から機体の改造に使えるものを発見。 任意の改造Lv+1。(上限:2Lv)'],
  135. [64..65, '強化 案機体を強化するための画期的なアイディアを思いつく。 任意の改造Lv+1。(上限:2Lv)'],
  136. [66..67, '懇願 整備班に頼みこみ、機体の改造をしてもらう。 任意の改造Lv+1。(上限:3Lv)'],
  137. [68..69, '掘出物 掘出物を発見、整備班が早速機体に取り付けてくれた。 任意の改造Lv+1。(上限:3Lv)'],
  138. [70..71, '募集 クルーの募集を行ったところ、何名か候補が現れた。 クルー1名を割安(20,000cdt)で雇用可。'],
  139. [72..73, '勧誘 有能な人材を発見した。ぜひ雇い入れたいものだが。 クルー1名を割安(20,000cdt)で雇用可。'],
  140. [74..75, '推薦 依頼人からの推薦で、クルーを1名紹介される。 クルー1名を割安(20,000cdt)で雇用可。'],
  141. [76..77, '志願 クルーとして雇って欲しい、という人物が現れる。クルー1名を割安(15,000cdt)で雇用可。'],
  142. [78..79, '成長 見習いクルーが大分成長してきた。もう1人前と見てもいい。クルー1名を割安(15,000cdt)で雇用可。'],
  143. [80..81, '交渉 依頼人との交渉がうまくいき、少し報酬を割増ししてもらえる。 チーム予算を8,000cdt獲得。'],
  144. [82..83, '節約 経費が思ったよりも節約できた。経理やオーナーの機嫌が良い。 チーム予算を8,000cdt獲得。'],
  145. [84..85, '賞金 今回の敵は賞金がかかっていたようで臨時収入が入った。 チーム予算を8,000cdt獲得。'],
  146. [86..87, '名声 チームの名声が高まっており、クルーの自尊心が刺激される。 チーム予算を12,000cdt獲得。'],
  147. [88..89, '一致団結 オーナーからの労いがあり、クルー一同の結束力が高まる。 チーム予算を12,000cdt獲得。'],
  148. [90..91, '点検 PC/クルー1名とシップに異状がないか点検作業を行う。 拠点AP+10。'],
  149. [92..93, '補修 整備班とともにくたびれたシップの改装作業を行う。 拠点AP+10。'],
  150. [94..95, '全面改修 艦内の問題箇所を全面的に改修する。 拠点AP+10。'],
  151. [96..97, '自由 行動自由気ままに好きなことをして過ごす。 00~49の任意の効果を適用可。(p69参照)'],
  152. [98..99, '歓迎 街の住民にたいへんな歓迎を受ける。 50~95の任意の効果を適用可。(p69参照)'],
  153. [100, '慰労 PC/クルー1名が、労ってくれる。 最大HP+4'],
  154. ]
  155. ),
  156. "SAL" => DiceTable::RangeTable.new(
  157. "サルベージ表",
  158. "1D100",
  159. [
  160. [1..2, '大失敗…。大変な損失を出してしまった…。 -5,000cdt'],
  161. [3..5, '失敗…。かなりの損失を出してしまった…。 -3,000cdt'],
  162. [6..9, '失敗…。損失を出してしまった…。 -1,000cdt'],
  163. [10, '大成功!大きな収益を上げることができた! +5,000cdt'],
  164. [11..19, '空振り……何の成果も得られなかった…。 0cdt'],
  165. [20, '掘り出し物を発見!2Lv改造済の【基本携行兵装】一つを獲得! 一般兵装(→p34)'],
  166. [21..22, 'ジャンク品を発見。船の装甲強化くらいには使えそうだ。 拠点AP+[5]'],
  167. [23..25, 'ジャンク品を発見。少し赤字だがまあやむを得まい。 +1,000cdt'],
  168. [26..29, 'ジャンク品を発見。手間賃くらいにはなった。 +2,000cdt'],
  169. [30, '掘り出し物を発見!2Lv改造済の【基本外装兵装】一つを獲得! 一般兵装(→p35)'],
  170. [31..32, '成功!少しだが利益を出すことができた! +3,000cdt'],
  171. [33..35, '成功!まずまずの利益を出すことができた! +5,000cdt'],
  172. [36..39, '大成功!大きな利益を出すことができた! +7,000cdt'],
  173. [40..41, '良質のバッテリーを獲得。 EP+[4]'],
  174. [42..43, '良質の装甲版を獲得。 AP+[4]'],
  175. [44, '大失敗…。大きな損失を出してしまった…。 -5,000cdt'],
  176. [45, 'ブレードを獲得。 →p34'],
  177. [46, 'ランスを獲得。 →p34'],
  178. [47, 'アンカーブレードを獲得。 →p34'],
  179. [48, 'パイルバンカーを獲得。 →p34'],
  180. [49, 'ハンドガンを獲得。 →p35'],
  181. [50, 'ヘビーハンドガンを獲得。 →p35'],
  182. [51, 'ライフルを獲得。 →p35'],
  183. [52, 'アンカーショットを獲得。 →p35'],
  184. [53, 'マシンガンSを獲得。 →p35'],
  185. [54, 'マシンガンLを獲得。 →p35'],
  186. [55, 'ミサイルポッドSを獲得。 →p35'],
  187. [56, 'ミサイルポッドLを獲得。 →p35'],
  188. [57, 'バズーカを獲得。 →p35'],
  189. [58, 'カノンを獲得。 →p35'],
  190. [59, 'ライトシールドを獲得。 →p35'],
  191. [60, 'ミドルシールドを獲得。 →p35'],
  192. [61, 'ヘビーシールドを獲得。 →p35'],
  193. [62, 'レーダーユニットを獲得。 →p35'],
  194. [63, 'ECMユニットを獲得。 →p35'],
  195. [64, 'サブブースターを獲得。 →p36'],
  196. [65, 'ディフェンスサポートを獲得。 →p36'],
  197. [66, 'コンバットサポートを獲得。 →p36'],
  198. [67, '大失敗…。大きな損失を出してしまった…。 -5,000cdt'],
  199. [68, 'ショットサポートを獲得。 →p36'],
  200. [69, 'パワーローダーを獲得。 →p36'],
  201. [70, 'サブバッテリーを獲得。 →p36'],
  202. [71, 'サブバッテリー+を獲得。 →p36'],
  203. [72, 'ファランクスを獲得。 →p36'],
  204. [73, 'リアクティブアーマーを獲得。 →p36'],
  205. [74, '強化装甲版を獲得。 →p36'],
  206. [75, 'ヘビーマシンガンSを獲得。 →p35'],
  207. [76, 'ヘビーマシンガンLを獲得。 →p35'],
  208. [77, '掘り出し物を発見!25,000cdt以下の【上級外装兵装】一つを獲得! 上級兵装 (→p37)'],
  209. [78..79, '失敗…。かなりの損失を出してしまった…。 -3,000cdt'],
  210. [80, '医療用品を獲得! 調息値+[1](全PC)'],
  211. [81, '大型ソーラーパネルを獲得! 整備値+[1](全PC)'],
  212. [82, '艦内用の環境設備を獲得! サポート使用回数+[1]'],
  213. [83, 'リニアガンを獲得。 →p37'],
  214. [84, 'リニアマシンガンを獲得。 →p37'],
  215. [85, 'ジャマ―ユニットを獲得。 →p37'],
  216. [86, 'センサー+を獲得。 →p37'],
  217. [87, 'パワーローダー++を獲得。 →p37'],
  218. [88, 'サブバッテリー++を獲得。 →p37'],
  219. [89, 'フレームカバーを獲得。 →p37'],
  220. [90, '空振り……何の成果も得られなかった…。 0cdt'],
  221. [91..92, '良質なA:GuSのパーツを獲得!機体の改造や予備パーツとして使えそうだ! 改造Lv+[1](上限:3Lv)'],
  222. [93..95, 'A:GuSのパーツを獲得!機体の改造や予備パーツとして使えそうだ。 改造Lv+[1](上限:1Lv)'],
  223. [96..98, '多少傷ついているが、A:GuS1機を獲得!→10,000cdtで売却可能→10,000cdt支払えば補修して取得が可能。 (→p30~33)(→w23)'],
  224. [99, 'A:GuS1機をほぼ完全な状態で獲得! (→p30~33)(→w23)'],
  225. [100, '掘り出し物を発見!25,000cdt以下の【上級携行兵装】一つを獲得! 上級兵装 (→p37)'],
  226. ]
  227. ),
  228. "DEF" => DiceTable::RangeTable.new(
  229. "赤字ペナルティー表",
  230. "1D10",
  231. [
  232. [1, '解雇 クルー1名を失う。10,000cdtを得る。'],
  233. [2..3, '劣化 任意のチーム能力一つは-1Lv。10,000cdtを得る。'],
  234. [4..5, '借金 次回の維持費が+20,000cdt。10,000cdtを得る。'],
  235. [6..7, '酷使 各PCは最大HP-4。10,000cdtを得る。'],
  236. [8..9, '売却 各PCはオプション以外の兵装を一つずつ廃棄。10,000cdtを得る。'],
  237. [10, '解雇 クルー1名を失う。10,000cdtを得る。'],
  238. ]
  239. ),
  240. # DiceTable::Tableが現状1D9に未対応
  241. "SPE" => DiceTable::Table.new(
  242. "特殊戦況表",
  243. "1D10",
  244. [
  245. '混戦 以下のエリアのユニットをシャッフルする。♠:A⇔C ♣:B⇔D ♦:A⇔D ♥:B⇔C',
  246. '乱戦 R中、すべての攻撃は[距離:○]になる。',
  247. '逸失 敵拠点エリアのユニットを[♠♣:A ♦♥:B]に移動。味方拠点エリアのユニットを[♠♣:D ♦♥:C]に移動。',
  248. '突風 艦船、オブジェクト以外の全ユニットを「風向き」方向に移動。',
  249. '流砂 以下のエリアのユニットは脱出のため、MPとEPを[3]点失う。[♠:A ♣:B ♦:C ♥:D]',
  250. '混乱 母船内でトラブル発生。R中、【整備】は行えない。[♠♥:味方側 ♣♦:敵側]',
  251. '岩盤 以下のエリアのユニットは岩盤に乗り上げ、《クリティカル》が1回発生。[♠:A ♣:B ♦:C ♥:D]',
  252. '混乱 R中、イニシア値を逆順で処理する。 ※【エイミング】等の高低も逆として処理する。',
  253. '飛礫 飛礫によって、すべてのユニットはAPを[1D10](以下のエリアでは[2D10])点失う。[♠:A ♣:B ♦:C ♥:D]',
  254. '雨 雨は砂を土へと変えてしまう。R中、全ユニット移動/突撃不可。',
  255. ]
  256. ),
  257. }.freeze
  258. 1 register_prefix_from_super_class()
  259. 1 register_prefix('-?\d*AGW', 'OMW', 'NMW', SECOND_ED_TABLES.keys)
  260. end
  261. end
  262. end

lib/bcdice/game_system/SamsaraBallad.rb

98.31% lines covered

96.43% branches covered

59 relevant lines. 58 lines covered and 1 lines missed.
28 total branches, 27 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/base'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class SamsaraBallad < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'SamsaraBallad'
  8. # ゲームシステム名
  9. 1 NAME = 'サンサーラ・バラッド'
  10. # ゲームシステム名の読みがな
  11. #
  12. # 「ゲームシステム名の読みがなの設定方法」(docs/dicebot_sort_key.md)を参考にして
  13. # 設定してください
  14. 1 SORT_KEY = 'さんさあらはらつと'
  15. # ダイスボットの使い方
  16. 1 HELP_MESSAGE = <<~MESSAGETEXT
  17. SB 通常のD100ロールを行う
  18. SBS スワップロールでD100ロールを行う
  19. SB#x@y F値をx、C値をyとして通常のD100ロールを行う
  20. SBS#x@y F値をx、C値をyとしてスワップロールでD100ロールを行う
  21. 例:
  22. SB<=85 通常の技能で成功率85%の判定
  23. SBS<=70 習熟を得た技能で成功率70%の判定
  24. SBS#3@7<=80 習熟を得た技能で、F値3、C値7で成功率80%の攻撃判定
  25. SB<57 通常の技能で、能動側の達成値が57の受動判定
  26. SBS<70 習熟を得た技能で、能動側の達成値が70の受動判定
  27. MESSAGETEXT
  28. # ダイスボットで使用するコマンドを配列で列挙する
  29. 1 register_prefix('SBS?')
  30. 1 def eval_game_system_specific_command(command)
  31. 54 debug("eval_game_system_specific_command Begin")
  32. 54 parser = Command::Parser.new('SBS', 'SB', round_type: round_type)
  33. .enable_critical
  34. .enable_fumble
  35. .restrict_cmp_op_to(nil, :<=, :<)
  36. 54 cmd = parser.parse(command)
  37. 54 else: 54 then: 0 unless cmd
  38. return nil
  39. end
  40. 54 then: 28 if cmd.command == 'SB'
  41. 28 places_text = nil
  42. 28 total = @randomizer.roll_once(100)
  43. else: 26 else
  44. 26 a = @randomizer.roll_once(10)
  45. 26 b = @randomizer.roll_once(10)
  46. 26 places_text = "#{a},#{b}"
  47. 78 then: 5 else: 47 places = [a, b].map { |n| n == 10 ? 0 : n }.sort
  48. 26 total = places[0] * 10 + places[1]
  49. 26 then: 2 else: 24 total = 100 if total == 0
  50. end
  51. 54 result = compare(total, cmd)
  52. result_str =
  53. 54 then: 16 if result.failure?
  54. 16 else: 38 "失敗"
  55. 38 then: 31 else: 7 elsif result.success?
  56. 31 "成功"
  57. end
  58. additional_str =
  59. 54 then: 9 if result.fumble?
  60. 9 else: 45 "ファンブル"
  61. 45 then: 8 else: 37 elsif result.critical?
  62. 8 "クリティカル"
  63. end
  64. sequence = [
  65. 54 "(D100#{cmd.cmp_op}#{cmd.target_number})",
  66. places_text,
  67. total.to_s,
  68. result_str,
  69. additional_str,
  70. ].compact
  71. 54 result.text = sequence.join(" > ")
  72. 54 return result
  73. end
  74. 1 private
  75. # @return [Result]
  76. 1 def compare(total, cmd)
  77. 54 then: 47 if [:<=, :<].include?(cmd.cmp_op)
  78. 47 then: 16 if !total.send(cmd.cmp_op, cmd.target_number)
  79. 16 else: 31 Result.failure(nil)
  80. 31 then: 8 elsif fumble_?(total, cmd.fumble)
  81. 8 Result.new.tap do |r|
  82. 8 r.success = true
  83. 8 r.fumble = true
  84. else: 23 end
  85. 23 then: 7 elsif critical_?(total, cmd.critical)
  86. 7 Result.critical(nil)
  87. else: 16 else
  88. 16 Result.success(nil)
  89. else: 7 end
  90. 7 elsif fumble_?(total, cmd.fumble)
  91. then: 1 # ファンブル優先
  92. 1 Result.new.tap do |r|
  93. 1 r.fumble = true
  94. else: 6 end
  95. 6 then: 1 elsif critical_?(total, cmd.critical)
  96. 1 Result.new.tap do |r|
  97. 1 r.critical = true
  98. end
  99. else: 5 else
  100. 5 Result.new
  101. end
  102. end
  103. # @param total [Integer]
  104. # @param fumble [Integer, nil]
  105. # @return [Boolean]
  106. 1 def fumble_?(total, fumble)
  107. 38 fumble && (total % 10 <= fumble)
  108. end
  109. # @param total [Integer]
  110. # @param critical [Integer, nil]
  111. # @return [Boolean]
  112. 1 def critical_?(total, critical)
  113. 29 critical && (total % 10 >= critical)
  114. end
  115. end
  116. end
  117. end

lib/bcdice/game_system/Satasupe.rb

98.03% lines covered

88.46% branches covered

203 relevant lines. 199 lines covered and 4 lines missed.
78 total branches, 69 branches covered and 9 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/satasupe/tables"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Satasupe < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'Satasupe'
  8. # ゲームシステム名
  9. 1 NAME = 'サタスペ'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'さたすへ'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・判定コマンド (nR>=x[y,z,c] or nR>=x or nR>=[,,c] etc)
  15.  nが最大ロール回数、xが難易度、yが目標成功度、zがファンブル値、cが必殺値。
  16.  y と z と c は省略可能です。(省略時、y=無制限、z=1、c=13(なし))
  17.  c の後ろにSを記述すると必殺が出た時点で判定を終了します。
  18.  例)5R>=5[10,2,7S]
  19. ・性業値コマンド(SRx or SRx+y or SRx-y x=性業値 y=修正値)
  20. ・各種表 : コマンド末尾に数字を入れると複数回の一括実行が可能 例)TAGT3
  21.  ・タグ決定表(TAGT)
  22.  ・命中判定ファンブル表(FumbleT)、致命傷表(FatalT)、
  23.    乗物致命傷表(FatalVT)
  24.  ・ロマンスファンブル表(RomanceFT)
  25.  ・アクシデント表(AccidentT)、汎用アクシデント表(GeneralAT)
  26.  ・その後表 (AfterT)、臭い飯表(KusaiMT)、登場表(EnterT)、
  27.    落とし前表(PayT)、時間切れ表(TimeUT)、バッドトリップ表(BudTT)
  28.  ・報酬表(Get〜) : ガラクタ(GetgT)、実用品(GetzT)、値打ち物(GetnT)、
  29.    奇天烈(GetkT)
  30.  ・NPCの年齢と好みを一括出力(NPCT)
  31.  ・「サタスペ」のベースとアクセサリを出力(GETSSTx xはアクセサリ数、省略時1)
  32. ・以下のコマンドは +,- でダイス目修正、=でダイス目指定が可能
  33.  例)CrimeIET+1 CrimeIET-1 CrimeIET=7
  34.  ・情報イベント表(〜IET) : 犯罪表(CrimeIET)、生活表(LifeIET)、
  35.    恋愛表(LoveIET)、教養表(CultureIET)、戦闘表(CombatIET)
  36.  ・情報ハプニング表(〜IHT) : 犯罪表(CrimeIHT)、生活表(LifeIHT)、
  37.    恋愛表(LoveIHT)、教養表(CultureIHT)、戦闘表(CombatIHT)
  38.  ・遭遇表(~RET):ミナミ遭遇表(MinamiRET)、中華街遭遇表(ChinatownRET)、
  39.    軍艦島遭遇表(WarshipLandRET)、官庁街遭遇表(CivicCenterRET)、
  40.    十三遭遇表(DowntownRET)、沙京遭遇表(ShaokinRET)、
  41.    らぶらぶ遭遇表(LoveLoveRET)、アジト遭遇表(AjitoRET)、
  42.    地獄湯遭遇表(JigokuSpaRET)、JAIL HOUSE遭遇表(JailHouseRET)
  43.  ・イベント表(~IT):治療イベント表(TreatmentIT)、大学イベント表(CollegeIT)
  44. ・D66ダイスあり
  45. INFO_MESSAGE_TEXT
  46. 1 register_prefix('\d+R', 'SR', 'TAGT', 'GETSST', 'NPCT', TABLES.keys, ALIASES.keys)
  47. 1 CREATE_ARMS_STRUCT = Struct.new(:base_parts, :accessory_parts, :parts_effect, :hit, :damage, :life, :kutibeni, :kiba, :abilities)
  48. 1 def initialize(command)
  49. 346 super(command)
  50. 346 @sort_add_dice = true
  51. 346 @d66_sort_type = D66SortType::ASC
  52. end
  53. 1 def eval_game_system_specific_command(command)
  54. 345 debug("eval_game_system_specific_command begin string", command)
  55. 345 result = checkRoll(command)
  56. 345 else: 271 then: 74 return result unless result.nil?
  57. 271 debug("判定ロールではなかった")
  58. 271 result = check_seigou(command)
  59. 271 else: 262 then: 9 return result unless result.empty?
  60. 262 debug("〔性業値〕チェックでもなかった")
  61. 262 debug("各種表として処理")
  62. 262 return rollTableCommand(command)
  63. end
  64. 1 def checkRoll(string)
  65. 345 debug("checkRoll begin string", string)
  66. 345 m = /^(\d+)R>=(\d+)(\[(\d+)?(,|,\d+)?(,\d+(S)?)?\])?$/i.match(string)
  67. 345 else: 74 then: 271 return nil unless m
  68. 74 roll_times = m[1].to_i
  69. 74 target = m[2].to_i
  70. 74 params = m[3]
  71. 74 min_suc, fumble, critical, is_critical_stop = get_roll_params(params)
  72. 74 result = ""
  73. 74 then: 1 else: 73 if target > 12
  74. 1 result += "【#{string}】 > 難易度が12を超えたため、超過分、ファンブル率が上昇!\n"
  75. 1 body: 1 while target > 12
  76. 1 target -= 1
  77. 1 fumble += 1
  78. end
  79. end
  80. 74 then: 66 else: 8 if (critical < 1) || (critical > 12)
  81. 66 critical = 13
  82. end
  83. 74 then: 3 else: 71 if fumble >= 6
  84. 3 result += "#{get_judge_info(target, fumble, critical)} > ファンブル率が6を超えたため自動失敗!"
  85. 3 return Result.failure(result)
  86. end
  87. 71 then: 1 else: 70 if target < 5
  88. 1 result += "【#{string}】 > あらゆる難易度は5未満にはならないため、難易度は5になる!\n"
  89. 1 target = 5
  90. end
  91. 71 dice_str, total_suc, is_critical, is_fumble = check_roll_loop(roll_times, min_suc, target, critical, fumble, is_critical_stop)
  92. 71 result += "#{get_judge_info(target, fumble, critical)} > #{dice_str} > 成功度#{total_suc}"
  93. 71 then: 17 else: 54 if is_fumble
  94. 17 result += " > ファンブル"
  95. end
  96. 71 then: 5 else: 66 if is_critical && (total_suc > 0)
  97. 5 result += " > 必殺発動可能!"
  98. end
  99. 71 debug('checkRoll result result', result)
  100. 71 return Result.new.tap do |r|
  101. 71 r.text = result
  102. 71 r.success = !is_fumble && min_suc > 0 && total_suc >= min_suc
  103. 71 r.failure = is_fumble
  104. 71 r.critical = is_critical
  105. 71 r.fumble = is_fumble
  106. end
  107. end
  108. 1 def get_roll_params(params)
  109. 74 min_suc = 0
  110. 74 fumble = 1
  111. 74 critical = 13
  112. 74 isCriticalStop = false
  113. # params => "[x,y,cS]"
  114. # ゲームシステムの識別子
  115. # ゲームシステム名
  116. # ゲームシステム名の読みがな
  117. # ダイスボットの使い方
  118. # params => "[x,y,cS]"
  119. 74 else: 24 then: 50 unless params.nil?
  120. 50 m = /\[(\d*)(,(\d*)?)?(,(\d*)(S)?)?\]/.match(params)
  121. 50 then: 50 else: 0 if m
  122. 50 min_suc = m[1].to_i
  123. 50 then: 40 else: 10 fumble = m[3].to_i if m[3].to_i != 0
  124. 50 then: 8 else: 42 critical = m[5].to_i if m[4]
  125. 50 isCriticalStop = !m[6].nil?
  126. end
  127. end
  128. 74 return min_suc, fumble, critical, isCriticalStop
  129. end
  130. 1 def get_judge_info(target, fumble, critical)
  131. 74 then: 66 else: 8 return "【難易度#{target}、ファンブル率#{fumble}、必殺#{critical == 13 ? 'なし' : critical.to_s}】"
  132. end
  133. 1 def check_roll_loop(roll_times, min_suc, target, critical, fumble, is_critical_stop)
  134. 71 dice_str = ''
  135. 71 is_fumble = false
  136. 71 is_critical = false
  137. 71 total_suc = 0
  138. 71 roll_times.times do |_i|
  139. 400 debug('roll_times', roll_times)
  140. 400 debug('min_suc, total_suc', min_suc, total_suc)
  141. # ゲームシステムの識別子
  142. # ゲームシステム名
  143. # ゲームシステム名の読みがな
  144. # ダイスボットの使い方
  145. # params => "[x,y,cS]"
  146. 400 then: 15 else: 385 if min_suc != 0 && (total_suc >= min_suc)
  147. 15 debug('(total_suc >= min_suc) break')
  148. 15 break
  149. end
  150. 385 d1 = @randomizer.roll_once(6)
  151. 385 d2 = @randomizer.roll_once(6)
  152. 385 dice_suc = 0
  153. 385 then: 271 else: 114 dice_suc = 1 if target <= (d1 + d2)
  154. 385 else: 71 then: 314 dice_str += "+" unless dice_str.empty?
  155. 385 dice_str += "#{dice_suc}[#{d1},#{d2}]"
  156. 385 total_suc += dice_suc
  157. 385 then: 9 else: 376 if critical <= d1 + d2
  158. 9 is_critical = true
  159. 9 dice_str += "『必殺!』"
  160. end
  161. 385 then: 17 else: 368 if (d1 == d2) && (d1 <= fumble) # ファンブルの確認
  162. 17 is_fumble = true
  163. 17 is_critical = false
  164. 17 break
  165. end
  166. 368 then: 4 else: 364 if is_critical && is_critical_stop # 必殺止めの確認
  167. 4 break
  168. end
  169. end
  170. 71 return dice_str, total_suc, is_critical, is_fumble
  171. end
  172. 1 def check_seigou(string)
  173. 271 debug("check_seigou begin string", string)
  174. 271 sr_parser = Command::Parser.new("SR", round_type: round_type)
  175. .has_suffix_number
  176. .restrict_cmp_op_to(nil)
  177. 271 cmd = sr_parser.parse(string)
  178. 271 else: 9 then: 262 return '' unless cmd
  179. 9 dice = @randomizer.roll_sum(2, 6)
  180. 9 diceTotal = dice + cmd.modify_number
  181. 9 target = cmd.suffix_number
  182. 9 then: 2 seigou = if target < diceTotal
  183. 2 else: 7 "「激」"
  184. 7 then: 5 elsif target > diceTotal
  185. 5 "「律」"
  186. else: 2 else # target == diceTotal
  187. 2 "「迷」"
  188. end
  189. 9 result = "〔性業値〕#{target}、「修正値」#{cmd.modify_number} > ダイス結果:(#{dice}) > #{dice}+(#{cmd.modify_number})=#{diceTotal} > #{seigou}"
  190. 9 then: 1 else: 8 result += " > 1ゾロのため〔性業値〕が1点上昇!" if dice == 2
  191. 9 then: 1 else: 8 result += " > 6ゾロのため〔性業値〕が1点減少!" if dice == 12
  192. 9 debug('check_seigou result result', result)
  193. 9 return result
  194. end
  195. ####################
  196. # 各種表
  197. 1 def rollTableCommand(command)
  198. 262 command = command.upcase
  199. 262 result = []
  200. 262 m = /([A-Za-z]+)(\d+)?(([+]|-|=)(\d+))?/.match(command)
  201. 262 else: 262 then: 0 return result unless m
  202. 262 command = m[1]
  203. 262 counts = 1
  204. 262 then: 6 else: 256 counts = m[2].to_i if m[2]
  205. 262 operator = m[4]
  206. 262 value = m[5].to_i
  207. 262 debug("eval_game_system_specific_command command", command)
  208. 262 case command
  209. when: 10 when "TAGT"
  210. 10 result = getTagTableResult(counts)
  211. when: 6 when "GETSST"
  212. 6 result = getCreateSatasupeResult(counts)
  213. when: 10 when "NPCT"
  214. 10 result = getNpcTableResult(counts)
  215. else: 236 else
  216. 236 result = getAnotherTableResult(command, counts, operator, value)
  217. end
  218. 262 return result.join("\n")
  219. end
  220. 1 def getTagTableResult(counts)
  221. 10 result = []
  222. 10 counts.times do |_i|
  223. 10 roll_result = TAG_TABLE.roll(@randomizer)
  224. 10 result.push("#{roll_result.table_name}:#{roll_result.value}:#{roll_result.body}")
  225. end
  226. 10 return result
  227. end
  228. 1 def getCreateSatasupeResult(counts)
  229. 6 debug("getCreateSatasupeResult counts", counts)
  230. 6 name = "サタスペ作成"
  231. 6 else: 0 arm = case @randomizer.roll_once(6)
  232. when: 5 when 1
  233. 5 CREATE_ARMS_STRUCT.new("「紙製の筒」", [], ["「命中:10、ダメージ:3、耐久度1」"], 10, 3, 1, 0, 0, [])
  234. when: 0 when 2
  235. CREATE_ARMS_STRUCT.new("「木製の筒」", [], ["「命中:9、ダメージ:3、耐久度2」"], 9, 3, 2, 0, 0, [])
  236. when: 0 when 3
  237. CREATE_ARMS_STRUCT.new("「小型のプラスチック製の筒」", [], ["「命中:9、ダメージ:4、耐久度2」"], 9, 4, 2, 0, 0, [])
  238. when: 0 when 4
  239. CREATE_ARMS_STRUCT.new("「大型のプラスチック製の筒」", [], ["「命中:8、ダメージ:3、耐久度2、両手」"], 8, 3, 2, 0, 0, ["「両手」"])
  240. when: 0 when 5
  241. CREATE_ARMS_STRUCT.new("「小型の金属製の筒」", [], ["「命中:9、ダメージ:4、耐久度3」"], 9, 4, 3, 0, 0, [])
  242. when: 1 when 6
  243. 1 CREATE_ARMS_STRUCT.new("「大型の金属製の筒」", [], ["「命中:8、ダメージ:5、耐久度3、両手」"], 8, 5, 3, 0, 0, ["「両手」"])
  244. end
  245. 6 counts.times do |_i|
  246. 9 part, effect, modifier = CREATE_ARMS_ACCESSORY_TABLE[@randomizer.roll_d66(D66SortType::ASC)]
  247. 9 arm.accessory_parts << part
  248. 9 arm.parts_effect << effect
  249. 9 modifier.call(arm, @randomizer)
  250. end
  251. 6 result = []
  252. 6 result.push("#{name}:ベース部品:#{arm.base_parts} アクセサリ部品:#{arm.accessory_parts.join}")
  253. 6 result.push("部品効果:#{arm.parts_effect.join}")
  254. 6 text = "完成品:サタスペ (ダメージ+#{arm.damage}・命中#{arm.hit}・射撃、"
  255. 6 then: 0 else: 6 text += "「(判定前宣言)#{arm.kutibeni}回だけ、必殺10」" if arm.kutibeni > 0
  256. 6 then: 1 else: 5 text += "「(判定前宣言)#{arm.kiba}回だけ、ダメージ+2」" if arm.kiba > 0
  257. 6 text += arm.abilities.sort.uniq.join
  258. 6 text += "「サタスペ#{counts}」「耐久度#{arm.life}」)"
  259. 6 result.push(text)
  260. 6 return result
  261. end
  262. 1 def getNpcTableResult(counts)
  263. 10 name = "NPC表:"
  264. 10 result = []
  265. 10 counts.times do |_i|
  266. 10 age, agen_const, agen_times = NPC_AGE_TABLE[@randomizer.roll_index(6)]
  267. 10 ysold = @randomizer.roll_sum(agen_times, 6) + agen_const
  268. 10 lmodValue = NPC_LMOOD_TABLE[@randomizer.roll_index(6)]
  269. 10 lageValue = NPC_LAGE_TABLE[@randomizer.roll_index(3)]
  270. 10 text = "#{name}#{age}(#{ysold}歳):#{lmodValue}#{lageValue}"
  271. 10 result.push(text)
  272. end
  273. 10 return result
  274. end
  275. 1 def getAnotherTableResult(command, counts, operator, value)
  276. 236 result = []
  277. 236 table_name = ALIASES[command] || command
  278. 236 table = TABLES[table_name]
  279. 236 then: 0 else: 236 return result if table.nil?
  280. 236 counts.times do |_i|
  281. 239 _, index = getTableIndex(operator, value, 2, 6)
  282. 239 info = table.choice(index)
  283. 239 text = "#{info.table_name}:#{info.value}:#{info.body}"
  284. 239 result.push(text)
  285. end
  286. 236 return result
  287. end
  288. 1 def getTableIndex(operator, value, diceCount, diceType)
  289. 239 index = nil
  290. 239 modify = 0
  291. 239 else: 228 case operator
  292. when: 4 when "+"
  293. 4 modify = value
  294. when: 5 when "-"
  295. 5 modify = value * -1
  296. when: 2 when "="
  297. 2 index = value
  298. end
  299. 239 then: 237 else: 2 if index.nil?
  300. 237 index = @randomizer.roll_sum(diceCount, diceType)
  301. 237 index += modify
  302. end
  303. 239 index = [index, diceCount * 1].max
  304. 239 index = [index, diceCount * diceType].min
  305. 239 return modify, index
  306. end
  307. end
  308. end
  309. end

lib/bcdice/game_system/ScreamHighSchool.rb

98.25% lines covered

80.77% branches covered

57 relevant lines. 56 lines covered and 1 lines missed.
26 total branches, 21 branches covered and 5 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/GardenOrder'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class ScreamHighSchool < GardenOrder
  6. # ゲームシステムの識別子
  7. 1 ID = 'ScreamHighSchool'
  8. # ゲームシステム名
  9. 1 NAME = 'スクリームハイスクール'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'すくりいむはいすくうる'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・基本判定
  15.  SHx/y@z x:成功率、y:連続攻撃回数(省略可)、z:クリティカル値(省略可)
  16.  (連続攻撃では1回の判定のみが実施されます)
  17.  例)SH55 SH(40-20) SH100/2 SH70@10 SH155/3@44
  18. ・感情判定
  19.  EMx@z x:成功率、z:クリティカル値(省略可)
  20.  例)EM50 EM50@15
  21. ・性格傾向判定
  22.  TRx@z x:成功率、z:クリティカル値(省略可)
  23.  例)TR60 TR60@15
  24. ・恐怖判定
  25.  FEx@z x:成功率、z:クリティカル値(省略可)
  26.  例)FE70 FE70@15
  27. ・負傷表
  28.  DCxxy
  29.  xx:属性(切断:SL,銃弾:BL,衝撃:IM,灼熱:BR,冷却:RF,電撃:EL)
  30.  y:ダメージ
  31.  例)DCSL7 DCEL22
  32. INFO_MESSAGE_TEXT
  33. 1 register_prefix(
  34. '(SH|SHS)',
  35. '(EM|TR|FE)',
  36. 'DC(SL|BL|IM|BR|RF|EL).+'
  37. )
  38. 1 def eval_game_system_specific_command(command)
  39. 61 else: 0 case command
  40. when: 13 when /(EM|TR|FE)(-?\d+)(@(\d+))?/i
  41. 13 command_type = Regexp.last_match(1).upcase
  42. 13 success_rate = Regexp.last_match(2).to_i
  43. 13 critical_border_text = Regexp.last_match(4)
  44. 13 critical_border = get_critical_border(critical_border_text, success_rate)
  45. 13 return check_roll_sh(success_rate, critical_border, command_type)
  46. when: 39 when %r{(SH|SHS)(-?\d+)(/(\d+))?(@(\d+))?}i
  47. 39 success_rate = Regexp.last_match(2).to_i
  48. 39 repeat_count = (Regexp.last_match(4) || 1).to_i
  49. 39 critical_border_text = Regexp.last_match(6)
  50. 39 critical_border = get_critical_border(critical_border_text, success_rate)
  51. 39 return check_roll_repeat_attack(success_rate, repeat_count, critical_border)
  52. when: 9 when /^DC(SL|BL|IM|BR|RF|EL)(\d+)/i
  53. 9 type = Regexp.last_match(1)
  54. 9 damage_value = Regexp.last_match(2).to_i
  55. 9 return look_up_damage_chart(type, damage_value)
  56. end
  57. return nil
  58. end
  59. 1 def check_roll_sh(success_rate, critical_border, command_type)
  60. 13 then: 1 else: 12 success_rate = 0 if success_rate < 0
  61. 13 then: 13 else: 0 fumble_border = (success_rate < 100 ? 96 : 99)
  62. 13 dice_value = @randomizer.roll_once(100)
  63. 13 result = get_check_result(dice_value, success_rate, critical_border, fumble_border)
  64. 13 title, supplementary = get_supplementary(command_type, result.text)
  65. 13 else: 0 then: 13 unless supplementary.empty?
  66. 13 supplementary = "(#{supplementary})"
  67. end
  68. 13 result.text = "#{title}判定 D100<=#{success_rate}@#{critical_border} > #{dice_value} > #{result.text}#{supplementary}"
  69. 13 return result
  70. end
  71. 1 def get_supplementary(command_type, result)
  72. 13 title = ''
  73. 13 supplementary = ''
  74. 13 else: 0 case command_type
  75. when: 4 when 'EM'
  76. 4 title = '感情'
  77. 4 else: 0 case result
  78. when: 1 when 'クリティカル'
  79. 1 supplementary = '次に行う判定の成功率に+50%'
  80. when: 1 when '成功'
  81. 1 supplementary = '次に行う判定の成功率に+30%'
  82. when: 1 when '失敗'
  83. 1 supplementary = '次に行う判定の成功率に-20%、呪縛+1点'
  84. when: 1 when 'ファンブル'
  85. 1 supplementary = '次に行う判定の成功率に-50%、呪縛+1D5点'
  86. end
  87. when: 4 when 'TR'
  88. 4 title = '性格傾向'
  89. 4 case result
  90. when: 1 when '失敗'
  91. 1 supplementary = '反対側の性格傾向で再判定する。あるいは、もしこれがその再判定の結果であればプレイヤーが性格傾向を選択する'
  92. when: 1 when 'ファンブル'
  93. 1 supplementary = '反対側の性格傾向に従い、呪縛+1D5点する。あるいは、もしこれが失敗後の再判定の結果だった場合、PCは混乱し行動を放棄するか逃げ出す。呪縛+2点'
  94. else: 2 else
  95. 2 supplementary = '判定した性格傾向に従う'
  96. end
  97. when: 5 when 'FE'
  98. 5 title = '恐怖'
  99. 5 case result
  100. when: 1 when '成功'
  101. 1 supplementary = 'ショックを受け流した。恐怖判定効果表の成功側の値分、呪縛が上昇する'
  102. when: 1 when '失敗'
  103. 1 supplementary = 'ショックを受けた。恐怖判定効果表の失敗側の値分、呪縛が上昇する'
  104. when: 1 when 'ファンブル'
  105. 1 supplementary = '深いショックを受けた。恐怖判定効果表の失敗側の値分に加え、さらに1D5点分、呪縛が上昇する'
  106. else: 2 else
  107. 2 supplementary = '何もショックを受けなかった'
  108. end
  109. end
  110. 13 return title, supplementary
  111. end
  112. end
  113. end
  114. end

lib/bcdice/game_system/Sengensyou.rb

100.0% lines covered

100.0% branches covered

29 relevant lines. 29 lines covered and 0 lines missed.
8 total branches, 8 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Sengensyou < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Sengensyou'
  7. # ゲームシステム名
  8. 1 NAME = '千幻抄'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'せんけんしよう'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・SGS 命中判定・回避判定
  14. INFO_MESSAGE_TEXT
  15. 1 register_prefix('SGS')
  16. 1 def eval_game_system_specific_command(command)
  17. # 命中判定・回避判定
  18. 7 parser = Command::Parser.new('SGS', round_type: @round_type).restrict_cmp_op_to(nil)
  19. 7 command = parser.parse(command)
  20. 7 else: 6 then: 1 unless command
  21. 1 return nil
  22. end
  23. 6 dice_list = @randomizer.roll_barabara(3, 6)
  24. 6 dice_total = dice_list.sum()
  25. 6 is_critical = dice_total >= 16
  26. 6 is_fumble = dice_total <= 5
  27. additional_text =
  28. 6 then: 2 if is_critical
  29. 2 else: 4 "クリティカル"
  30. 4 then: 2 else: 2 elsif is_fumble
  31. 2 "ファンブル"
  32. end
  33. 6 then: 3 else: 3 modify_text = "#{dice_total}#{Format.modifier(command.modify_number)}" if command.modify_number != 0
  34. sequence = [
  35. 6 "(3D6#{Format.modifier(command.modify_number)})",
  36. "#{dice_total}[#{dice_list.join(',')}]",
  37. modify_text,
  38. 6 (dice_total + command.modify_number).to_s,
  39. additional_text,
  40. ].compact
  41. 6 result = Result.new.tap do |r|
  42. 6 r.text = sequence.join(" > ")
  43. 6 r.critical = is_critical
  44. 6 r.fumble = is_fumble
  45. end
  46. 6 return result
  47. end
  48. end
  49. end
  50. end

lib/bcdice/game_system/SevenFortressMobius.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/NightWizard'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class SevenFortressMobius < NightWizard
  6. # ゲームシステムの識別子
  7. 1 ID = 'SevenFortressMobius'
  8. # ゲームシステム名
  9. 1 NAME = 'セブン=フォートレス メビウス'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'せふんふおおとれすめひうす'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・判定用コマンド (nSFM+m@x#y)
  15.  "(基本値)SFM(常時および常時に準じる特技等及び状態異常(省略可))@(クリティカル値)#(ファンブル値)(常時以外の特技等及び味方の支援効果等の影響(省略可))"でロールします。
  16.  Rコマンド(2R6m[n,m]c[x]f[y]>=t tは目標値)に読替されます。
  17.  クリティカル値、ファンブル値が無い場合は1や13などのあり得ない数値を入れてください。
  18.  例)12SFM-5@7#2  1SFM  50SFM+5@7,10#2,5 50SFM-5+10@7,10#2,5+15+25
  19. INFO_MESSAGE_TEXT
  20. 1 register_prefix('([-+]?\d+)?SFM', '2R6')
  21. 1 def initialize(command)
  22. 4 super(command)
  23. 4 @nw_command = "SFM"
  24. end
  25. end
  26. end
  27. end

lib/bcdice/game_system/ShadowRun.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class ShadowRun < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'ShadowRun'
  7. # ゲームシステム名
  8. 1 NAME = 'シャドウラン'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'しやとうらん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = "上方無限ロール(xUn)の境界値を6にセットします。\n"
  13. 1 def initialize(command)
  14. 29 super(command)
  15. 29 @sort_add_dice = true
  16. 29 @sort_barabara_dice = true
  17. 29 @upper_dice_reroll_threshold = 6
  18. end
  19. end
  20. end
  21. end

lib/bcdice/game_system/ShadowRun4.rb

100.0% lines covered

100.0% branches covered

22 relevant lines. 22 lines covered and 0 lines missed.
4 total branches, 4 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class ShadowRun4 < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'ShadowRun4'
  7. # ゲームシステム名
  8. 1 NAME = 'シャドウラン 4th Edition'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'しやとうらん4'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. 個数振り足しロール(xRn)の境界値を6にセット、バラバラロール(xBn)の目標値を5以上にセットします。
  14. BコマンドとRコマンド時に、グリッチの表示を行います。
  15. INFO_MESSAGE_TEXT
  16. 1 def initialize(command)
  17. 82 super(command)
  18. 82 @sort_add_dice = true
  19. 82 @sort_barabara_dice = true
  20. 82 @reroll_dice_reroll_threshold = 6 # RerollDiceで振り足しをする出目の閾値
  21. 82 @default_cmp_op = :>=
  22. 82 @default_target_number = 5
  23. end
  24. # シャドウラン4版用グリッチ判定
  25. 1 def grich_text(numberSpot1, dice_cnt_total, successCount)
  26. 36 dice_cnt_total_half = (1.0 * dice_cnt_total / 2)
  27. 36 debug("dice_cnt_total_half", dice_cnt_total_half)
  28. 36 else: 6 then: 30 unless numberSpot1 >= dice_cnt_total_half
  29. 30 return nil
  30. end
  31. # グリッチ!
  32. 6 then: 4 if successCount == 0
  33. 4 'クリティカルグリッチ'
  34. else: 2 else
  35. 2 'グリッチ'
  36. end
  37. end
  38. end
  39. end
  40. end

lib/bcdice/game_system/ShadowRun5.rb

100.0% lines covered

100.0% branches covered

43 relevant lines. 43 lines covered and 0 lines missed.
6 total branches, 6 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/ShadowRun4'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class ShadowRun5 < ShadowRun4
  6. # ゲームシステムの識別子
  7. 1 ID = 'ShadowRun5'
  8. # ゲームシステム名
  9. 1 NAME = 'シャドウラン 5th Edition'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'しやとうらん5'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. 個数振り足しロール(xRn)の境界値を6にセット、バラバラロール(xBn)の目標値を5以上にセットします。
  15. バラバラロール(xBn)のみ、リミットをセットできます。リミットの指定は(xBn@l)のように指定します。(省略可)
  16. BコマンドとRコマンド時に、グリッチの表示を行います。
  17. INFO_MESSAGE_TEXT
  18. 1 register_prefix('(\d+)B6@(\d+)')
  19. 1 def initialize(command)
  20. 46 super(command)
  21. 46 @sort_add_dice = true
  22. 46 @sort_barabara_dice = true
  23. 46 @reroll_dice_reroll_threshold = 6 # RerollDiceで振り足しをする出目の閾値
  24. 46 @default_cmp_op = :>=
  25. 46 @default_target_number = 5
  26. end
  27. # シャドウラン5版 リミット時のテスト
  28. 1 def eval_game_system_specific_command(command)
  29. 2 debug('chatch limit prefix')
  30. 2 m = /(\d+B6)@(\d+)/.match(command)
  31. 2 b_dice = m[1]
  32. 2 limit = m[2].to_i
  33. 2 output_before_limited = BCDice::CommonCommand::BarabaraDice.eval(b_dice, self, @randomizer).text
  34. 2 m = /成功数(\d+)/.match(output_before_limited)
  35. 2 output_after_limited = output_before_limited
  36. 2 before_suc_cnt = m[1].to_i
  37. 2 then: 1 else: 1 if before_suc_cnt > limit
  38. 1 after_suc_cnt = limit
  39. 1 over_suc_cnt = before_suc_cnt - limit
  40. 1 output_after_limited = output_before_limited.gsub(/成功数(\d+)/, "成功数#{after_suc_cnt}")
  41. 1 output_after_limited += "(リミット超過#{over_suc_cnt})"
  42. end
  43. 2 output = output_after_limited
  44. 2 output = output.gsub('B', 'B6')
  45. 2 output = output.gsub('6>=5', "[6]Limit[#{limit}]>=5")
  46. 2 debug(output)
  47. 2 return output
  48. end
  49. # シャドウラン5版用グリッチ判定
  50. 1 def grich_text(numberSpot1, dice_cnt_total, successCount)
  51. 46 dice_cnt_total_half = dice_cnt_total.to_f / 2
  52. 46 debug("dice_cnt_total_half", dice_cnt_total_half)
  53. 46 else: 8 then: 38 unless numberSpot1 > dice_cnt_total_half
  54. 38 return nil
  55. end
  56. # グリッチ!
  57. 8 then: 6 if successCount == 0
  58. 6 'クリティカルグリッチ'
  59. else: 2 else
  60. 2 'グリッチ'
  61. end
  62. end
  63. end
  64. end
  65. end

lib/bcdice/game_system/SharedFantasia.rb

100.0% lines covered

95.0% branches covered

31 relevant lines. 31 lines covered and 0 lines missed.
20 total branches, 19 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class SharedFantasia < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'SharedFantasia'
  7. # ゲームシステム名
  8. 1 NAME = 'Shared†Fantasia'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'しえああとふあんたしあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. 2D6の成功判定に 自動成功、自動失敗、致命的失敗、劇的成功 の判定があります。
  14. SF/ST = 2D6のショートカット
  15. 例) SF+4>=9 : 2D6して4を足した値が9以上なら成功
  16. MESSAGETEXT
  17. 1 register_prefix('SF', 'ST')
  18. 1 def change_text(string)
  19. 28 string.gsub(/S[FT]/i, "2D6")
  20. end
  21. 1 def result_2d6(total, dice_total, _dice_list, cmp_op, target)
  22. 12 then: 1 else: 11 return Result.nothing if target == '?'
  23. 11 else: 11 then: 0 return nil unless [:>=, :>].include?(cmp_op)
  24. 11 critical = false
  25. 11 fumble = false
  26. 11 then: 2 if dice_total == 12
  27. 2 else: 9 critical = true
  28. 9 then: 2 else: 7 elsif dice_total == 2
  29. 2 fumble = true
  30. end
  31. 11 then: 9 else: 2 totalValueBonus = (cmp_op == :>= ? 1 : 0)
  32. 11 then: 5 if (total + totalValueBonus) > target
  33. 5 then: 1 if critical
  34. 1 else: 4 Result.critical("自動成功(劇的成功)")
  35. 4 then: 1 elsif fumble
  36. 1 Result.failure("自動失敗")
  37. else: 3 else
  38. 3 Result.success("成功")
  39. end
  40. else: 6 else
  41. 6 then: 1 if critical
  42. 1 else: 5 Result.success("自動成功")
  43. 5 then: 1 elsif fumble
  44. 1 Result.fumble("自動失敗(致命的失敗)")
  45. else: 4 else
  46. 4 Result.failure("失敗")
  47. end
  48. end
  49. end
  50. end
  51. end
  52. end

lib/bcdice/game_system/ShinMegamiTenseiKakuseihen.rb

100.0% lines covered

90.0% branches covered

42 relevant lines. 42 lines covered and 0 lines missed.
10 total branches, 9 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class ShinMegamiTenseiKakuseihen < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'ShinMegamiTenseiKakuseihen'
  7. # ゲームシステム名
  8. 1 NAME = '真・女神転生TRPG 覚醒篇'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'しんめかみてんせいTRPGかくせいへん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定
  14. 1D100<=(目標値) でスワップ・通常・逆スワップ判定を判定。
  15. 威力ダイスは nU6[6] (nはダイス個数)でロール可能です。
  16. INFO_MESSAGE_TEXT
  17. # ゲーム別成功度判定(1d100)
  18. 1 def check_1D100(total, dice_total, cmp_op, target)
  19. 12 then: 1 else: 11 return '' if target == '?'
  20. 11 else: 11 then: 0 return '' unless cmp_op == :<=
  21. 11 dice1, dice2 = split_tens(dice_total)
  22. 11 total1 = dice1 * 10 + dice2
  23. 11 total2 = dice2 * 10 + dice1
  24. # ゾロ目
  25. 11 isRepdigit = (dice1 == dice2)
  26. 11 result = " > スワップ"
  27. 11 result += getCheckResultText(target, [total1, total2].min, isRepdigit)
  28. 11 result += "/通常"
  29. 11 result += getCheckResultText(target, total % 100, isRepdigit)
  30. 11 result += "/逆スワップ"
  31. 11 result += getCheckResultText(target, [total1, total2].max, isRepdigit)
  32. 11 return result
  33. end
  34. 1 def split_tens(value)
  35. 11 value %= 100
  36. 11 ones = value / 10
  37. 11 tens = value % 10
  38. 11 return [ones, tens]
  39. end
  40. 1 def getCheckResultText(diff, total, isRepdigit)
  41. 33 checkResult = getCheckResult(diff, total, isRepdigit)
  42. 33 text = format("(%02d)", total) + checkResult
  43. 33 return text
  44. end
  45. 1 def getCheckResult(diff, total, isRepdigit)
  46. 33 then: 20 else: 13 if diff >= total
  47. 20 return getSuccessResult(isRepdigit)
  48. end
  49. 13 return getFailResult(isRepdigit)
  50. end
  51. 1 def getSuccessResult(isRepdigit)
  52. 20 then: 6 else: 14 if isRepdigit
  53. 6 return "絶対成功"
  54. end
  55. 14 return "成功"
  56. end
  57. 1 def getFailResult(isRepdigit)
  58. 13 then: 6 else: 7 if isRepdigit
  59. 6 return "絶対失敗"
  60. end
  61. 7 return "失敗"
  62. end
  63. end
  64. end
  65. end

lib/bcdice/game_system/ShinkuuGakuen.rb

99.36% lines covered

94.44% branches covered

156 relevant lines. 155 lines covered and 1 lines missed.
54 total branches, 51 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class ShinkuuGakuen < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'ShinkuuGakuen'
  7. # ゲームシステム名
  8. 1 NAME = '真空学園'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'しんくうかくえん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定
  14. RLx:技能ベースxで技能チェックのダイスロール
  15. RLx>=y:この書式なら目標値 y で判定結果出力
  16.  例)RL10  RL22>=50
  17. ・武器攻撃
  18. (武器記号)(技能ベース値)
  19.  例)SW10 BX30
  20. 武器を技能ベースでダイスロール。技発動までチェック。
  21. 武器記号は以下の通り
  22.  SW:剣、LS:大剣、SS:小剣、SP:槍、
  23.  AX:斧、CL:棍棒、BW:弓、MA:体術、
  24.  BX:ボクシング、PR:プロレス、ST:幽波紋
  25. ・カウンター攻撃
  26. カウンター技は武器記号の頭に「C」をつけるとロール可能。
  27.  例)CSW10 CBX76
  28. MESSAGETEXT
  29. 1 register_prefix(
  30. 'CRL', 'CSW', 'CLS', 'CSS', 'CSP', 'CAX', 'CCL', 'CMA', 'CBX', 'CPR', 'CST',
  31. 'RL', 'SW', 'LS', 'SS', 'SP', 'AX', 'CL', 'BW', 'MA', 'BX', 'PR', 'ST'
  32. )
  33. 1 def eval_game_system_specific_command(command)
  34. 44 m = /^([A-Z]+)([+-]?\d+)?(?:>=(\d+))?$/i.match(command)
  35. 44 else: 44 then: 0 unless m
  36. return nil
  37. end
  38. 44 weaponCommand = m[1]
  39. 44 base = m[2].to_i
  40. 44 diff = m[3]
  41. 44 weaponInfo = getWeaponTable(weaponCommand)
  42. 44 output_msg = rollJudge(base, diff, weaponInfo)
  43. 44 return output_msg
  44. end
  45. 1 def rollJudge(base, diff, weaponInfo)
  46. 44 debug("rollJudge base", base)
  47. 44 debug("rollJudge diff", diff)
  48. 44 weaponName = weaponInfo[:name]
  49. 44 weaponTable = weaponInfo[:table]
  50. 44 diceList = getJudgeDiceList
  51. 44 total = diceList.sum()
  52. 44 allTotal = total + base
  53. 44 then: 33 else: 11 diffText = diff.nil? ? "" : ">=#{diff}"
  54. 44 result = "(#{weaponName}:#{base}#{diffText}) > 1D100+#{base} > #{total}"
  55. 44 then: 14 else: 30 result += "[#{diceList.join(',')}]" if diceList.length >= 2
  56. 44 result += "+#{base}"
  57. 44 result += " > #{allTotal}"
  58. 44 result += getSuccessText(allTotal, diff, diceList, weaponTable)
  59. 44 result += getWeaponSkillText(weaponTable, diceList.max)
  60. 44 debug("check_1D100 result", result)
  61. 44 return result
  62. end
  63. 1 def getJudgeDiceList
  64. 44 diceList = []
  65. 44 loop do
  66. 68 value = @randomizer.roll_once(100)
  67. 68 diceList << value
  68. 68 rank01 = value % 10
  69. 68 debug("rank01", rank01)
  70. 68 else: 24 then: 44 break unless rank01 == 0
  71. end
  72. 44 return diceList
  73. end
  74. 1 def getSuccessText(allTotal, diff, diceList, isWeapon)
  75. 44 first = diceList.first
  76. 44 then: 0 else: 44 return '' if first.nil?
  77. 44 then: 1 else: 43 return " > ファンブル" if first <= 9
  78. 43 then: 31 else: 12 if diff.nil? && (first != 10)
  79. 31 return ''
  80. end
  81. 12 result = ''
  82. 12 skillText = getSkillText(first, diff, isWeapon)
  83. 12 result += skillText
  84. 12 else: 2 then: 10 unless diff.nil?
  85. 10 then: 1 else: 9 result += ' > ' if skillText.empty?
  86. 10 then: 6 else: 4 success = (allTotal >= diff.to_i ? "成功" : "失敗")
  87. 10 result += success.to_s
  88. end
  89. 12 return result
  90. end
  91. 1 def getSkillText(first, diff, isWeapon)
  92. 12 result = ''
  93. 12 then: 2 else: 10 return result if isWeapon
  94. 10 result = ' > '
  95. 10 else: 3 then: 7 return result unless first == 10
  96. 3 result += "技能なし:ファンブル"
  97. 3 then: 1 else: 2 return result if diff.nil?
  98. 2 result += "/技能あり:"
  99. 2 return result\
  100. end
  101. 1 def getWeaponTable(weaponCommand)
  102. 44 debug('getWeaponTable weaponCommand', weaponCommand)
  103. 44 else: 14 case weaponCommand.upcase
  104. when: 2 when 'SW'
  105. 2 return getWeaponTableSword
  106. when: 4 when 'CSW'
  107. 4 return getWeaponTableSwordCounter
  108. when: 1 when 'LS'
  109. 1 return getWeaponTableLongSword
  110. when: 1 when 'CLS'
  111. 1 return getWeaponTableLongSwordCounter
  112. when: 2 when 'SS'
  113. 2 return getWeaponTableShortSword
  114. when: 1 when 'CSS'
  115. 1 return getWeaponTableShortSwordCounter
  116. when: 1 when 'SP'
  117. 1 return getWeaponTableSpear
  118. when: 2 when 'CSP'
  119. 2 return getWeaponTableSpearCounter
  120. when: 1 when 'AX'
  121. 1 return getWeaponTableAx
  122. when: 1 when 'CAX'
  123. 1 return getWeaponTableAxCounter
  124. when: 1 when 'CL'
  125. 1 return getWeaponTableClub
  126. when: 1 when 'CCL'
  127. 1 return getWeaponTableClubCounter
  128. when: 1 when 'BW'
  129. 1 return getWeaponTableBow
  130. when: 2 when 'MA'
  131. 2 return getWeaponTableMartialArt
  132. when: 2 when 'CMA'
  133. 2 return getWeaponTableMartialArtCounter
  134. when: 1 when 'BX'
  135. 1 return getWeaponTableBoxing
  136. when: 1 when 'CBX'
  137. 1 return getWeaponTableBoxingCounter
  138. when: 1 when 'PR'
  139. 1 return getWeaponTableProWrestling
  140. when: 1 when 'CPR'
  141. 1 return getWeaponTableProWrestlingCounter
  142. when: 2 when 'ST'
  143. 2 return getWeaponTableStand
  144. when: 1 when 'CST'
  145. 1 return getWeaponTableStandCounter
  146. end
  147. 14 return {name: '判定', table: nil}
  148. end
  149. 1 def getWeaponTableSword
  150. 2 {name: '剣',
  151. table: [[11, '失礼剣', '成功度+5'],
  152. [22, '隼斬り', '回避不可'],
  153. [33, 'みじん斬り', '攻撃量2倍'],
  154. [44, '天地二段', '2連続攻撃'],
  155. [55, '波動剣', 'カウンター不可、B・D'],
  156. [66, '疾風剣', '攻撃量3倍、盾受けー100'],
  157. [77, '残像剣', '全体攻撃、B・D'],
  158. [88, '五月雨斬り」', '回避不可.ダメージ3倍'],
  159. [99, 'ライジングノヴア」', '2連続攻撃・2撃目敵無防備、B・D'],
  160. [0, '光速剣', '攻撃量3倍、盾受け不可、カウンター不可、B・D'],]}
  161. end
  162. 1 def getWeaponTableSwordCounter
  163. 4 {name: '剣カウンター',
  164. table: [[33, 'パリィ', '攻撃の無効化'],
  165. [44, nil, nil],
  166. [55, nil, nil],
  167. [66, 'かすみ青眼', 'カウンター'],
  168. [77, nil, nil],
  169. [88, nil, nil],
  170. [99, nil, nil],
  171. [0, '不動剣', 'クロスカウンター、B・D、ダメージ2倍'],]}
  172. end
  173. 1 def getWeaponTableLongSword
  174. 1 {name: '大剣',
  175. table: [[11, 'スマッシュ', '敵防御半分'],
  176. [22, '峰打ち', '麻痺硬化「根性」0'],
  177. [33, '水鳥剣', '敵防御判定ー50'],
  178. [44, 'ブルクラッシュ', '敵防御力無視'],
  179. [55, '逆風の太刀', 'カウンター不可、ダメージ2倍'],
  180. [66, '濁流剣', '回避不可、カウンター不可、B・D'],
  181. [77, '清流剣', '回避不可、カウンター不可、B・D'],
  182. [88, '燕返し', '2連続攻撃・2撃目カウンター不可、B・D'],
  183. [99, '地ずり残月', '盾受け不可、ダメージ3倍、B・D'],
  184. [0, '乱れ雪月花', '3連続攻撃・三撃目敵無防備、ダメージ3倍、防御力無視、B・D'],]}
  185. end
  186. 1 def getWeaponTableLongSwordCounter
  187. 1 {name: '大剣カウンター',
  188. table: [[22, '無形の位', '攻撃の無効化'],
  189. [33, nil, nil],
  190. [44, nil, nil],
  191. [55, '双破', 'クロスカウンター、B・D'],
  192. [66, nil, nil],
  193. [77, nil, nil],
  194. [88, '喪心無想', 'カウンター、攻撃量6倍'],
  195. [99, nil, nil],
  196. [0, nil, nil],]}
  197. end
  198. 1 def getWeaponTableShortSword
  199. 2 {name: '小剣',
  200. table: [[11, '乱れ突き', '2連続攻撃'],
  201. [22, 'フェイクタング', 'スタン効果「注意力」5'],
  202. [33, 'マインドステア', '麻痺効果「注意力」0'],
  203. [44, 'サイドワインダー', '成功度+3、盾受け不可'],
  204. [55, 'スクリュードライバー', '防御力無視、ダメージ2倍'],
  205. [66, 'ニードルロンド', '3連続攻撃'],
  206. [77, 'プラズマブラスト', '麻痺効果「根性」0、B・D'],
  207. [88, 'サザンクロス', '麻痺効果「根性」5、攻撃量2倍'],
  208. [99, 'ファイナルレター', '気絶効果「根性」0、回避不可、カウンター不可、B・D'],
  209. [0, '百花繚乱', '回避不可、盾受け不可、攻撃量3倍、B・D'],]}
  210. end
  211. 1 def getWeaponTableShortSwordCounter
  212. 1 {name: '小剣カウンター',
  213. table: [[11, 'リポスト', 'カウンター'],
  214. [22, nil, nil],
  215. [33, nil, nil],
  216. [44, nil, nil],
  217. [55, nil, nil],
  218. [66, nil, nil],
  219. [77, nil, nil],
  220. [88, 'マタドール', 'カウンター、麻痺効果「注意力」5'],
  221. [99, nil, nil],
  222. [0, 'マリオネット', '攻撃の相手を変える'],]}
  223. end
  224. 1 def getWeaponTableSpear
  225. 1 {name: '槍',
  226. table: [[11, 'チャージ', 'ダメージ1.5倍、盾受けー30'],
  227. [22, '稲妻突き', '回避不可'],
  228. [33, '脳削り', '麻痺効果「根性」0'],
  229. [44, '大車輪', '全体攻撃'],
  230. [55, '狂乱撃', '二回攻撃'],
  231. [66, 'スパイラルチャージ', '盾受け不可、ダメージ2倍、B・D'],
  232. [77, '双龍波', 'スタン効果「注意力」5、盾受け不可、B・D'],
  233. [88, '流星衝', 'カウンター不可、ダメージ3倍、次行動まで攻撃対象にならない'],
  234. [99, 'ランドスライサー', '全体攻撃、回避不可、カウンター不可、B・D'],
  235. [0, '無双三段', '三段攻撃、二段目B・D、三段目ダメージ2倍、B・D'],]}
  236. end
  237. 1 def getWeaponTableSpearCounter
  238. 2 {name: '槍カウンター',
  239. table: [[55, '風車', 'カウンター、ダメージ2倍'],
  240. [66, nil, nil],
  241. [77, nil, nil],
  242. [88, nil, nil],
  243. [99, nil, nil],
  244. [0, nil, nil],]}
  245. end
  246. 1 def getWeaponTableAx
  247. 1 {name: '斧',
  248. table: [[11, '一人時間差', '防御行動ー100'],
  249. [22, 'トマホーク', 'カウンター不可'],
  250. [33, '大木断', 'ダメージ2倍'],
  251. [44, 'ブレードロール', '全体攻撃'],
  252. [55, 'マキ割りスペシャル', '盾受け不可、B・D'],
  253. [66, 'ヨーヨー', 'カウンター不可、2連続攻撃'],
  254. [77, 'メガホーク', 'カウンター不可、全体攻撃、攻撃量2倍'],
  255. [88, 'デッドリースピン', '回避不可、攻撃量5倍'],
  256. [99, 'マキ割りダイナミック', '盾受け不可、ダメージ2倍、B・D、ターンの最後に命中'],
  257. [0, '高速ナブラ', '回避不可、カウンター不可、攻撃量3倍、B・D'],]}
  258. end
  259. 1 def getWeaponTableAxCounter
  260. 1 {name: '斧カウンター',
  261. table: [[44, '真っ向唐竹割り', 'クロスカウンター、B・D'],
  262. [55, nil, nil],
  263. [66, nil, nil],
  264. [77, nil, nil],
  265. [88, nil, nil],
  266. [99, nil, nil],
  267. [0, nil, nil],]}
  268. end
  269. 1 def getWeaponTableClub
  270. 1 {name: '棍棒',
  271. table: [[11, 'ハードヒット', '防御力無視'],
  272. [22, 'ダブルヒット', '2連続攻撃'],
  273. [33, '回転撃', '防御判定ー100'],
  274. [44, '飛翔脳天撃', '麻痺効果「根性」5'],
  275. [55, '削岩撃', '盾受け不可、攻撃量3倍'],
  276. [66, '地裂撃', '防御力無視、カウンター不可、盾受け不可、スタン効果「注意力」0'],
  277. [77, 'トリプルヒット', '3連続攻撃'],
  278. [88, '亀甲羅割り', '防御力半分、盾受け不可、B・D'],
  279. [99, '叩きつぶす', '防御力無視、防御行動、カウンター不可、B・D'],
  280. [0, 'グランドクロス', '防御無視、盾、カウンター不可、ダメージ2倍、B・D、全体攻撃'],]}
  281. end
  282. 1 def getWeaponTableClubCounter
  283. 1 {name: '棍棒カウンター',
  284. table: [[11, 'ブロッキング', '攻撃の無効化'],
  285. [22, nil, nil],
  286. [33, nil, nil],
  287. [44, nil, nil],
  288. [55, nil, nil],
  289. [66, 'ジャストミート', '飛び道具のみカウンター'],
  290. [77, nil, nil],
  291. [88, nil, nil],
  292. [99, 'ホームラン', 'すべての攻撃に対するカウンター'],
  293. [0, nil, nil],]}
  294. end
  295. 1 def getWeaponTableBow
  296. 1 {name: '弓',
  297. table: [[11, '影縫い', '麻痺効果「注意力」0'],
  298. [22, 'アローレイン', '全体攻撃・回避ー50'],
  299. [33, '速射', '2連続攻撃'],
  300. [44, '瞬速の矢', '防御不可'],
  301. [55, 'バラージシュート', '全体攻撃・盾受け不可・攻撃量2倍'],
  302. [66, '貫きの矢', '防御力無視、B・D'],
  303. [77, '落鳳波', '回避不可、B・D'],
  304. [88, '皆死ね矢', '全体攻撃、気絶効果「根性」5'],
  305. [99, 'ミリオンダラー', '三連続攻撃'],
  306. [0, '夢想弓', 'B・D、ダメージ3倍'],]}
  307. end
  308. 1 def getWeaponTableMartialArt
  309. 4 {name: '体術',
  310. table: [[11, '集気法', '通常ダメージ分自分のHP回復'],
  311. [22, 'コンビネーション', '2連続攻撃'],
  312. [33, '逆一本', '盾受け不可、防御力半分、スタン効果「根性」0'],
  313. [44, 'コークスクリューブロー', '防御力無視、ダメージ3倍'],
  314. [55, '練気拳', '全体攻撃・回避不可'],
  315. [66, 'バベルクランプル', '盾受け不可、B・D'],
  316. [77, 'マシンガンジャブ', '3連続攻撃'],
  317. [88, 'ナイアガラフォール', '盾受け不可、B・D、ダメージ2倍'],
  318. [99, '羅刹掌', '防御力無視、防御不可、B・D、ダメージ3倍'],
  319. [0, '千手観音', '5連続攻撃、すべてカウンター不可'],]}
  320. end
  321. 1 def getWeaponTableMartialArtCounter
  322. 2 {name: '体術カウンター',
  323. table: [[11, 'スウェイバック', '攻撃の無効化'],
  324. [22, nil, nil],
  325. [33, '当て身投げ', 'カウンター'],
  326. [44, nil, nil],
  327. [55, nil, nil],
  328. [66, 'ジョルトカウンター', 'クロスカウンター、B・D'],
  329. [77, nil, nil],
  330. [88, nil, nil],
  331. [99, 'ガードキャンセル', 'D10で振った必殺技によるカウンター' + getRandMartialArtCounter],
  332. [0, nil, nil],]}
  333. end
  334. 1 def getRandMartialArtCounter
  335. 2 value = @randomizer.roll_once(10)
  336. 2 dice = value * 10 + value
  337. 2 then: 0 else: 2 dice = 100 if value == 110
  338. 2 tableInfo = getWeaponTableMartialArt
  339. 2 weaponTable = tableInfo[:table]
  340. 2 result = " > (#{value})"
  341. 2 result += getWeaponSkillText(weaponTable, dice)
  342. 2 return result
  343. end
  344. 1 def getWeaponTableBoxing
  345. 1 {name: 'ボクシング',
  346. table: [[11, 'ワン・ツー', '2連続攻撃・2攻撃目盾受け、回避不可'],
  347. [22, 'リバーブロー', '麻痺効果「根性」5'],
  348. [33, 'フリッカー', '2連続攻撃・全て盾受け、カウンター不可'],
  349. [44, 'コークスクリューブロー', '防御力無視、ダメージ3倍'],
  350. [55, 'レイ・ガン', '全体攻撃、B・D、陽属性魔法攻撃'],
  351. [66, 'ショットガンブロー', '攻撃量10倍'],
  352. [77, 'ハートブレイクショット', '2連続攻撃・1攻撃目防御力無視、ダメージ3倍・2撃目敵無防備'],
  353. [88, 'デンプシーロール', '3連続攻撃・全てB・D'],
  354. [99, 'フラッシュピストンマッハパンチ', '全体攻撃、B・D、気絶効果「根性」5'],
  355. [0, '右', '防御力無視、ダメージ10倍'],]}
  356. end
  357. 1 def getWeaponTableBoxingCounter
  358. 1 {name: 'ボクシングカウンター',
  359. table: [[11, 'ダッキングブロー', 'カウンター'],
  360. [22, 'ジョルトカウンター', 'クロスカウンター、B・D'],
  361. [33, nil, nil],
  362. [44, nil, nil],
  363. [55, nil, nil],
  364. [66, nil, nil],
  365. [77, nil, nil],
  366. [88, nil, nil],
  367. [99, nil, nil],
  368. [0, 'ノーガード戦法', '攻撃の無効化、次ターン以降は自分の盾受け、回避不可、全ての攻撃にB・D'],]}
  369. end
  370. 1 def getWeaponTableProWrestling
  371. 1 {name: 'プロレス',
  372. table: [[11, 'ボディスラム', '盾受け不可'],
  373. [22, 'ドロップキック', 'B・D'],
  374. [33, '水車落とし', '盾受け不可、成功度+5'],
  375. [44, 'ナックルアロー', 'B・D、麻痺効果「根性」5'],
  376. [55, 'ワン・ツー・エルボー', '2連続攻撃'],
  377. [66, 'バックドロップ', '盾受け不可、ダメージ2倍'],
  378. [77, '投げっ放しジャーマン', '盾受け不可、防御力無視、成功度+5'],
  379. [88, 'パワーボム', '盾受け不可、ダメージ2倍、B・D'],
  380. [99, 'デスバレーボム', '盾受け不可、防御力無視、ダメージ2倍、気絶効果「根性」5'],
  381. [0, 'ジャックハマー', '盾受け不可、防御力無視、ダメージ3倍、成功度+10'],]}
  382. end
  383. 1 def getWeaponTableProWrestlingCounter
  384. 1 {name: 'プロレスカウンター',
  385. table: [[22, 'パワースラム', 'カウンター'],
  386. [55, 'アックスボンバー', 'カウンター、B・D'],
  387. [66, nil, nil],
  388. [77, nil, nil],
  389. [88, nil, nil],
  390. [99, nil, nil],
  391. [0, nil, nil],]}
  392. end
  393. 1 def getWeaponTableStand
  394. 2 {name: '幽波紋',
  395. table: [[11, 'SILER CHARIOT', '攻撃量5倍、刺しタイプ攻撃'],
  396. [22, 'TOWER OF GRAY', '防御力無視'],
  397. [33, 'DARK BLUE MOON', '全体攻撃、攻撃量2倍、水属性斬りタイプ攻撃'],
  398. [44, 'EMPEROR', '回避不可、盾受け不可、カウンター不可、飛び道具攻撃'],
  399. [55, 'MAGICIAN\'s RED', 'ダメージ2倍、B・D、火属性魔法攻撃'],
  400. [66, 'DEATH 13', 'ダメージ0、全体攻撃、気絶効果「根性」5'],
  401. [77, 'HIEROPHANT GREEN', '全体攻撃、B・D、水属性攻撃'],
  402. [88, 'VANILLA ICE CREAM', '盾受け不可、カウンター不可、防御力無視、ダメージ3倍、B・D'],
  403. [99, 'THE WORLD', '5連続攻撃、全て敵無防備'],
  404. [0, 'STAR PLATINUM', '攻撃量15倍、B・D'],]}
  405. end
  406. 1 def getWeaponTableStandCounter
  407. 1 {name: '幽波紋カウンター',
  408. table: [[11, 'ANUBIS', '技のみカウンター、ダメージ(カウンターした回数の2乗)倍、斬りタイプ攻撃'],
  409. [22, nil, nil],
  410. [33, nil, nil],
  411. [44, nil, nil],
  412. [55, nil, nil],
  413. [66, 'YELLOW TEMPERANE', '魔法・飛び道具含めて全ての攻撃を無効化'],
  414. [77, nil, nil],
  415. [88, nil, nil],
  416. [99, nil, nil],
  417. [0, nil, nil],]}
  418. end
  419. 1 def getWeaponSkillText(weaponTable, dice)
  420. 46 debug('getWeaponSkillText', dice)
  421. 46 then: 14 else: 32 return '' if weaponTable.nil?
  422. 32 preName = ''
  423. 32 preEffect = ''
  424. 32 weaponTable.each do |index, name, effect|
  425. 190 name ||= preName
  426. 190 preName = name
  427. 190 effect ||= preEffect
  428. 190 preEffect = effect
  429. 190 else: 28 then: 162 next unless index == (dice % 100)
  430. 28 return " > 「#{name}」#{effect}"
  431. end
  432. 4 return ''
  433. end
  434. end
  435. end
  436. end

lib/bcdice/game_system/ShinobiGami.rb

100.0% lines covered

96.67% branches covered

72 relevant lines. 72 lines covered and 0 lines missed.
30 total branches, 29 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/dice_table/table'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class ShinobiGami < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'ShinobiGami'
  8. # ゲームシステム名
  9. 1 NAME = 'シノビガミ'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'しのひかみ'
  12. # ダイスボットの使い方
  13. # 25/01/17:書式成形(半角スペース×2に統一、同じ書籍のシーン表は改行なしで列挙)
  14. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  15. ・行為判定 nSG@s#f>=x
  16. 2D6の行為判定を行う。ダイス数が指定された場合、大きい出目2個を採用する。
  17. n: ダイス数 (省略時 2)
  18. s: スペシャル値 (省略時 12)
  19. f: ファンブル値 (省略時 2)
  20. x: 目標値 (省略可)
  21. 例)SG, SG@11, SG@11#3, SG#3>=7, 3SG>=7
  22. ・行為判定以外の表
  23. 以下の表は「回数+コマンド」で複数回振れる
  24. 例)3RCT, 2WT
  25. ・ランダム特技決定表 RTTn (n:分野番号、省略可能)
  26. 1器術 2体術 3忍術 4謀術 5戦術 6妖術
  27. ・ランダム分野表 RCT
  28. ・各種表:基本ルールブック以降
  29. ファンブル表 FT、戦場表 BT、感情表 ET、変調表 WT、戦国変調表 GWT、プライズ効果表 PT
  30. 妖魔化(異形表、妖魔忍法表一括) MT、異形表 MTR、妖魔忍法表(x:A,B,C) DSx
  31. ・各種表:流派ブック以降
  32. 比良坂流派ブック
  33. パニック表 HRPT
  34. 鞍馬流派ブック
  35. 新戦場表 BNT
  36. 御斎流派ブック
  37. 覚醒表 OTAT
  38. 忍法授業シーン表(x:1-攻撃系 2-防御系 3-戦略系)NCTx
  39. 【数奇】OTS
  40. 隠忍流派ブック
  41. 妖術変調対応表(x:なし-現代/戦国、1-現代、2-戦国)YWTx
  42. 妖魔化(新異形表利用) NMT、新異形表 NMTR、妖魔忍法表(x:1-異霊 2-凶身 3-神化 4-攻激)DSNx
  43. 出物表 ONDT
  44. ・各種表:基本ルールブック改訂版以前
  45. 無印
  46. 旧ファンブル表 OFT 、旧変調表 OWT、旧戦場表 OBT、異形表 MT
  47. 怪ファンブル表 KFT、怪変調表 KWT (基本ルールブックと同一)
  48. ・シーン表
  49. 基本ルールブック
  50. 通常 ST、出島 DST、都市 CST、館 MST、トラブル TST、回想 KST、日常 NST、学校 GAST、戦国 GST
  51. 忍秘伝
  52. 中忍試験 HC、滅びの塔 HT、影の街 HK、夜行列車 HY、病院 HO、龍動 HR、密室 HM、催眠 HS
  53. 正忍記
  54. カジノ TC、ロードムービー TRM、マスカレイド・キャッスル TMC、月天に死の咲く TGS、恋人との日々 TKH、学校(黒星祭) TKG、魔都学園 TMG、魔都東京 TMT
  55. 流派ブック以降
  56. 御斎流派ブック
  57. 不良高校 OTFK
  58. 基本ルールブック改訂版以前
  59. 東京 TKST
  60. リプレイ戦1〜2巻
  61. 京都 KYST、神社仏閣 JBST
  62. その他
  63. 秋空に雪舞えば AKST、夏の終わり NTST、出島EX DXST、災厄 CLST、斜歯ラボ HLST、培養プラント PLST
  64. ・D66ダイスあり
  65. INFO_MESSAGE_TEXT
  66. 1 class DemonSkillTableForMetamorphose
  67. 1 def initialize(pretext, table)
  68. 7 @pretext = pretext
  69. 7 @table = table
  70. end
  71. 1 def roll(randomizer)
  72. 3 return "#{@pretext} > #{@table.roll(randomizer)}"
  73. end
  74. end
  75. 1 def initialize(command)
  76. 162 super(command)
  77. 162 @sort_add_dice = true
  78. 162 @d66_sort_type = D66SortType::ASC
  79. end
  80. 1 SPECIAL = "スペシャル(【生命力】1点か変調一つを回復)"
  81. 1 def result_2d6(total, dice_total, _dice_list, cmp_op, target)
  82. 8 else: 8 then: 0 return nil unless cmp_op == :>=
  83. 8 then: 2 if dice_total <= 2
  84. 2 else: 6 Result.fumble("ファンブル")
  85. 6 then: 2 elsif dice_total >= 12
  86. 2 else: 4 Result.critical(SPECIAL)
  87. 4 then: 1 elsif target == "?"
  88. 1 else: 3 nil
  89. 3 then: 2 elsif total >= target
  90. 2 Result.success("成功")
  91. else: 1 else
  92. 1 Result.failure("失敗")
  93. end
  94. end
  95. 1 register_prefix('\d*SG')
  96. 1 def eval_game_system_specific_command(command)
  97. 151 return action_roll(command) || repeat_table(command)
  98. end
  99. 1 def repeat_table(command)
  100. 133 then: 3 else: 130 times = command.start_with?(/\d/) ? command.to_i : 1
  101. 133 key = command.sub(/^\d+/, '')
  102. 133 results = [*0...times].map do |_|
  103. 133 roll_tables(key, TABLES) || roll_tables(key, SCENE_TABLES) ||
  104. roll_tables(key, DEMON_SKILL_TABLES) || roll_tables(key, DEMON_SKILL_TABLES_NEW) || RTT.roll_command(@randomizer, key)
  105. end.compact
  106. 133 then: 2 else: 131 return nil if results.empty?
  107. 131 return results.join("\n")
  108. end
  109. 1 RTT = DiceTable::SaiFicSkillTable.new(
  110. [
  111. ['器術', ['絡繰術', '火術', '水術', '針術', '仕込み', '衣装術', '縄術', '登術', '拷問術', '壊器術', '掘削術']],
  112. ['体術', ['騎乗術', '砲術', '手裏剣術', '手練', '身体操術', '歩法', '走法', '飛術', '骨法術', '刀術', '怪力']],
  113. ['忍術', ['生存術', '潜伏術', '遁走術', '盗聴術', '腹話術', '隠形術', '変装術', '香術', '分身の術', '隠蔽術', '第六感']],
  114. ['謀術', ['医術', '毒術', '罠術', '調査術', '詐術', '対人術', '遊芸', '九ノ一の術', '傀儡の術', '流言の術', '経済力']],
  115. ['戦術', ['兵糧術', '鳥獣術', '野戦術', '地の利', '意気', '用兵術', '記憶術', '見敵術', '暗号術', '伝達術', '人脈']],
  116. ['妖術', ['異形化', '召喚術', '死霊術', '結界術', '封術', '言霊術', '幻術', '瞳術', '千里眼の術', '憑依術', '呪術']],
  117. ],
  118. s_format: "『%<category_name>s』%<skill_name>s",
  119. rtt_format: "ランダム指定特技表(%<category_dice>d,%<row_dice>d) > %<text>s"
  120. )
  121. 1 private
  122. 1 def action_roll(command)
  123. 151 parser = Command::Parser.new(/\d*SG/, round_type: round_type)
  124. .restrict_cmp_op_to(:>=, nil)
  125. .enable_critical
  126. .enable_fumble
  127. 151 cmd = parser.parse(command)
  128. 151 else: 20 then: 131 return nil unless cmd
  129. 20 then: 7 else: 13 times = cmd.command.start_with?(/\d/) ? cmd.command.to_i : 2
  130. 20 then: 2 else: 18 return nil if times <= 1
  131. 18 cmd.critical ||= 12
  132. 18 cmd.fumble ||= 2
  133. 18 dice_list_full = @randomizer.roll_barabara(times, 6).sort
  134. 18 then: 4 else: 14 dice_list_full_str = "[#{dice_list_full.join(',')}]" if times > 2
  135. 18 dice_list = dice_list_full[-2, 2]
  136. 18 dice_total = dice_list.sum()
  137. 18 total = dice_total + cmd.modify_number
  138. result =
  139. 18 then: 6 if dice_total <= cmd.fumble
  140. 6 else: 12 Result.fumble("ファンブル")
  141. 12 then: 5 elsif dice_total >= cmd.critical
  142. 5 else: 7 Result.critical(SPECIAL)
  143. 7 then: 2 elsif cmd.cmp_op.nil?
  144. 2 else: 5 Result.new
  145. 5 then: 3 elsif total >= cmd.target_number
  146. 3 Result.success("成功")
  147. else: 2 else
  148. 2 Result.failure("失敗")
  149. end
  150. sequence = [
  151. 18 "(#{cmd.to_s(:after_modify_number)})",
  152. dice_list_full_str,
  153. "#{dice_total}[#{dice_list.join(',')}]#{Format.modifier(cmd.modify_number)}",
  154. total,
  155. result.text
  156. ].compact
  157. 18 result.text = sequence.join(" > ")
  158. 18 result
  159. end
  160. # 妖魔忍法表A, B, C
  161. DEMON_SKILL_TABLES = {
  162. 1 'DSA' => DiceTable::Table.new(
  163. '妖魔忍法表A',
  164. '1D6',
  165. [
  166. '【震々】(怪p.252/基本p.172)',
  167. '【神隠】(怪p.252/基本p.172)',
  168. '【夜雀】(怪p.252/基本p.172)',
  169. '【猟犬】(怪p.252/基本p.172)',
  170. '【逢魔時】(怪p.252/基本p.172)',
  171. '【狂骨】(怪p.252/基本p.172)',
  172. ]
  173. ),
  174. 'DSB' => DiceTable::Table.new(
  175. '妖魔忍法表B',
  176. '1D6',
  177. [
  178. '【野衾】(怪p.253/基本p.172)',
  179. '【付喪神】(怪p.253/基本p.172)',
  180. '【見越】(怪p.253/基本p.172)',
  181. '【木魂】(怪p.253/基本p.172)',
  182. '【鵺】(怪p.253/基本p.172)',
  183. '【生剥】(怪p.253/基本p.172)',
  184. ]
  185. ),
  186. 'DSC' => DiceTable::Table.new(
  187. '妖魔忍法表C',
  188. '1D6',
  189. [
  190. '【百眼】(怪p.254/基本p.173)',
  191. '【呑口】(怪p.254/基本p.173)',
  192. '【荒吐】(怪p.254/基本p.173)',
  193. '【怨霊】(怪p.254/基本p.173)',
  194. '【鬼火】(怪p.254/基本p.173)',
  195. '【蛭子】(怪p.254/基本p.173)',
  196. ]
  197. )
  198. }.freeze
  199. # 妖魔忍法表(隠忍流派)
  200. DEMON_SKILL_TABLES_NEW = {
  201. 1 'DSN1' => DiceTable::Table.new(
  202. '妖魔忍法表・異霊',
  203. '1D6',
  204. [
  205. '【逢魔時】(基本 p172)/【虚舟】(隠忍 p28)',
  206. '【神隠】(基本 p172)/【夢喰】(隠忍 p28)',
  207. '【狂骨】(基本 p172)/【金毛】(隠忍 p28)',
  208. '【木魂】(基本 p172)/【朽縄】(隠忍 p28)',
  209. '【付喪神】(基本 p172)/【香魂】(隠忍 p28)',
  210. '【生剥】(基本 p172)/【三尸】(隠忍 p28)',
  211. ]
  212. ),
  213. 'DSN2' => DiceTable::Table.new(
  214. '妖魔忍法表・凶身',
  215. '1D6',
  216. [
  217. '【荒吐】(基本 p173)/【赤舌】(隠忍 p29)',
  218. '【鬼火】(基本 p173)/【大太郎】(隠忍 p29)',
  219. '【怨霊】(基本 p173)/【白面】(隠忍 p29)',
  220. '【呑口】(基本 p173)/【邪魅】(隠忍 p29)',
  221. '【百眼】(基本 p173)/【鬼胎】(隠忍 p29)',
  222. '【蛭子】(基本 p173)/【岩肌】(隠忍 p29)',
  223. ]
  224. ),
  225. 'DSN3' => DiceTable::Table.new(
  226. '妖魔忍法表・神化',
  227. '1D6',
  228. [
  229. '【鵺】(基本 p172)/【朱盤】(隠忍 p29)',
  230. '【野衾】(基本 p172)/【長壁】(隠忍 p29)',
  231. '【震々】(基本 p172)/【物気】(隠忍 p29)',
  232. '【見越】(基本 p172)/【紙舞】(隠忍 p29)',
  233. '【夜雀】(基本 p172)/【目競】(隠忍 p29)',
  234. '【猟犬】(基本 p172)/【置行】(隠忍 p29)',
  235. ]
  236. ),
  237. 'DSN4' => DiceTable::Table.new(
  238. '妖魔忍法表・攻激',
  239. '1D6',
  240. [
  241. '【黒手】(隠忍 p28)/【強威】(隠忍 p25)',
  242. '【業弓】(隠忍 p28)/【強威】(隠忍 p25)',
  243. '【怪病】(隠忍 p28)/【強威】(隠忍 p25)',
  244. '【鏖殺】(隠忍 p28)/【強威】(隠忍 p25)',
  245. '【精霊風】(隠忍 p28)/【強威】(隠忍 p25)',
  246. '【雷獣】(隠忍 p28)/【強威】(隠忍 p25)',
  247. ]
  248. )
  249. }.freeze
  250. TABLES = {
  251. 1 'FT' => DiceTable::Table.new(
  252. 'ファンブル表',
  253. '1D6',
  254. [
  255. '何か調子がおかしい。そのサイクルの間、すべての行為判定にマイナス1の修正がつく。',
  256. 'しまった! 好きな忍具を1つ失ってしまう。',
  257. '情報が漏れる! あなた以外のキャラクターは、あなたの持っている【秘密】か【居所】の中から、好きなものをそれぞれ一つ知ることができる。',
  258. '油断した! 術の制御に失敗し、好きな【生命力】を1点失う。',
  259. '敵の陰謀か? 罠にかかり、ランダムに選んだ変調一つを受ける。変調は、変調表で決定すること。',
  260. 'ふう。危ないところだった。特に何も起こらない。',
  261. ]
  262. ),
  263. 'OFT' => DiceTable::Table.new(
  264. 'ファンブル表(旧文庫版)',
  265. '1D6',
  266. [
  267. '何か調子がおかしい。そのサイクルの間、すべての行為判定にマイナス1の修正がつく。',
  268. 'しまった! 好きな忍具を1つ失ってしまう。',
  269. '情報が漏れる! このゲームであなたが獲得した【秘密】は、他のキャラクター全員の知るところとなる。',
  270. '油断した! 術の制御に失敗し、好きな【生命力】を1点失う。',
  271. '敵の陰謀か? 罠にかかり、ランダムに選んだ変調1つを受ける。変調は、変調表で決定すること。',
  272. 'ふう。危ないところだった。特に何も起こらない。',
  273. ]
  274. ),
  275. 'KFT' => DiceTable::Table.new(
  276. '怪ファンブル表',
  277. '1D6',
  278. [
  279. '何か調子がおかしい。そのサイクルの間、すべての行為判定にマイナス1の修正がつく。',
  280. 'しまった! 好きな忍具を1つ失ってしまう。',
  281. '情報が漏れる! あなた以外のキャラクターは、あなたの持っている【秘密】か【居所】の中から、好きなものをそれぞれ一つ知ることができる。',
  282. '油断した! 術の制御に失敗し、好きな【生命力】を1点失う。',
  283. '敵の陰謀か? 罠にかかり、ランダムに選んだ変調一つを受ける。変調は、変調表で決定すること。',
  284. 'ふう。危ないところだった。特に何も起こらない。',
  285. ]
  286. ),
  287. 'ET' => DiceTable::Table.new(
  288. '感情表',
  289. '1D6',
  290. [
  291. '共感(プラス)/不信(マイナス)',
  292. '友情(プラス)/怒り(マイナス)',
  293. '愛情(プラス)/妬み(マイナス)',
  294. '忠誠(プラス)/侮蔑(マイナス)',
  295. '憧憬(プラス)/劣等感(マイナス)',
  296. '狂信(プラス)/殺意(マイナス)',
  297. ]
  298. ),
  299. 'WT' => DiceTable::Table.new(
  300. '変調表',
  301. '1D6',
  302. [
  303. '故障:すべての忍具が使用不能になる。この効果は累積しない。各サイクルの終了時に、《絡繰術》で行為判定を行い、成功するとこの変調は無効化される。',
  304. 'マヒ:修得している特技の中からランダムに一つを選び、その特技が使用不能になる。この効果は、修得している特技の数だけ累積する。各サイクルの終了時に、《身体操術》で行為判定を行い、成功するとこの変調はすべて無効化される。',
  305. '重傷:命中判定、情報判定、感情判定を行うたびに、接近戦ダメージを1点受ける。この効果は累積しない。各サイクルの終了時に、《生存術》で行為判定を行い、成功するとこの変調は無効化される。',
  306. '行方不明:メインフェイズ中、自分以外がシーンプレイヤーのシーンに登場することができなくなる。この効果は累積しない。各サイクルの終了時に、《経済力》で行為判定を行い、成功するとこの変調は無効化される。',
  307. '忘却:修得している【感情】の中からランダムに一つを選び、その【感情】を持っていないものとして扱う。この効果は、修得している【感情】の数だけ累積する。各サイクルの終了時に、《記憶術》で行為判定を行い、成功するとこの変調はすべて無効化される。',
  308. '呪い:修得している忍法の中からランダムに一つを選び、その忍法を修得していないものとして扱う。この効果は、修得している忍法の数だけ累積する。各サイクルの終了時に、《呪術》で行為判定を行い、成功するとこの変調はすべて無効化される。',
  309. ]
  310. ),
  311. 'OWT' => DiceTable::Table.new(
  312. '変調表(旧文庫版)',
  313. '1D6',
  314. [
  315. '故障:すべての忍具が使用不能。1サイクルの終了時に、《絡繰術》で判定を行い、成功するとこの効果は無効化される。',
  316. 'マヒ:修得済み特技がランダムに1つ使用不能になる。1サイクルの終了時に、《身体操術》で成功するとこの効果は無効化される。',
  317. '重傷:次の自分の手番に行動すると、ランダムな特技分野1つの【生命力】に1点ダメージ。1サイクルの終了時に、《生存術》で成功すると無効化される。',
  318. '行方不明:その戦闘終了後、メインフェイズ中に行動不可。1サイクルの終了時に、《経済力》で成功すると無効化される。',
  319. '忘却:修得済み感情がランダムに1つ使用不能。1サイクルの終了時に、《記憶術》で成功すると無効化される。',
  320. '呪い:修得済み忍法がランダムに1つ使用不能。1サイクルの終了時に、《呪術》で成功すると無効化される。',
  321. ]
  322. ),
  323. 'KWT' => DiceTable::Table.new(
  324. '怪変調表',
  325. '1D6',
  326. [
  327. '故障:すべての忍具が使用不能になる。この効果は累積しない。各サイクルの終了時に、《絡繰術》で行為判定を行い、成功するとこの変調は無効化される。',
  328. 'マヒ:修得している特技の中からランダムに一つを選び、その特技が使用不能になる。この効果は、修得している特技の数だけ累積する。各サイクルの終了時に、《身体操術》で行為判定を行い、成功するとこの変調はすべて無効化される。',
  329. '重傷:命中判定、情報判定、感情判定を行うたびに、接近戦ダメージを1点受ける。この効果は累積しない。各サイクルの終了時に、《生存術》で行為判定を行い、成功するとこの変調は無効化される。',
  330. '行方不明:メインフェイズ中、自分以外がシーンプレイヤーのシーンに登場することができなくなる。この効果は累積しない。各サイクルの終了時に、《経済力》で行為判定を行い、成功するとこの変調は無効化される。',
  331. '忘却:修得している【感情】の中からランダムに一つを選び、その【感情】を持っていないものとして扱う。この効果は、修得している【感情】の数だけ累積する。各サイクルの終了時に、《記憶術》で行為判定を行い、成功するとこの変調はすべて無効化される。',
  332. '呪い:修得している忍法の中からランダムに一つを選び、その忍法を修得していないものとして扱う。この効果は、修得している忍法の数だけ累積する。各サイクルの終了時に、《呪術》で行為判定を行い、成功するとこの変調はすべて無効化される。',
  333. ]
  334. ),
  335. 'GWT' => DiceTable::Table.new(
  336. '戦国変調表',
  337. '1D6',
  338. [
  339. '催眠:この変調を受けた者は、戦闘に参加したとき、戦闘開始時、もしくはこの変調を受けたときに【生命力】を1点減少しないと、その戦闘から自動的に脱落する。この効果は累積しない。サイクルの終了時に、《意気》の判定を行い、成功するとこの効果は無効化される。',
  340. '火達磨:この変調を受けた者は、ファンブル値が1上昇し、ファンブル時に1点の接近戦ダメージを受ける。この効果は累積する。シーンの終了時に、この効果は無効化される。',
  341. '猛毒:この変調を受けた者は、戦闘に参加した時、ラウンドの終了時にサイコロを1個振る。その目が奇数だったら、【生命力】を1点減少する。この効果は累積する。サイクルの終了時に、《毒術》の判定を行い、成功するとこの効果は無効化される。',
  342. '飢餓:この変調を受けた者は、戦闘に参加した時、ラウンドの終了時にサイコロを1個振る。その目が偶数だったら、【生命力】を1点減少する。この効果は累積する。サイクルの終了時に、《兵糧術》の判定を行い、成功するとこの効果は無効化される。',
  343. '残刃:この変調を受けた者は、回復判定や忍法、忍具の効果によって【生命力】を回復できなくなる(変調を回復することはできる)。この効果は累積しない。サイクルの終了時に、《拷問術》の判定を行い、成功するとこの効果は無効化される。',
  344. '野望:この変調を受けた者は、命中判定にプラス1、それ以外のあらゆる行為判定にマイナス1の修正がつく。この効果は累積しない。サイクルの終了時に、《憑依術》の判定を行い、成功するとこの効果は無効化される。',
  345. ]
  346. ),
  347. 'OBT' => DiceTable::Table.new(
  348. '戦場表(旧文庫版)',
  349. '1D6',
  350. [
  351. '平地:特になし。',
  352. '水中:海や川や、プール、血の池地獄など。この戦場では、回避判定に-2の修正がつく。',
  353. '高所:ビルの谷間や樹上、断崖絶壁など。この戦場でファンブルすると1点のダメージを受ける。',
  354. '悪天候:嵐や吹雪、ミサイルの雨など。この戦場では、すべての攻撃忍法の間合が1上昇する。',
  355. '雑踏:人混みや教室、渋滞中の車道など。この戦場では、行為判定のとき、2D6の目がプロット値+1以下だとファンブルする。',
  356. '極地:宇宙や深海、溶岩、魔界など。ラウンドの終わりにGMが1D6を振り、経過ラウンド以下なら全員1点ダメージ。ここから脱落したものは変調表を適用する。',
  357. ]
  358. ),
  359. 'BT' => DiceTable::Table.new(
  360. '戦場表',
  361. '1D6',
  362. [
  363. '平地:特になし。',
  364. '水中:海や川や、プール、血の池地獄など。この戦場では、回避判定にマイナス2の修正がつく。',
  365. '高所:ビルの谷間や樹上、断崖絶壁など。この戦場でファンブルすると接近戦ダメージを1点受ける。',
  366. '悪天候:嵐や吹雪、ミサイルの雨など。この戦場では、すべての攻撃忍法の間合が1上昇する。',
  367. '雑踏:人混みや教室、渋滞中の車道など。この戦場では、この戦場では、行為判定のとき、ファンブル値が1上昇する。',
  368. '極地:宇宙や深海、溶岩、魔界など。ゲームマスターは、ラウンドの終わりに1D6を振る。戦闘開始時からの経過ラウンド以下の目が出ると、この戦場にいると、接近戦ダメージを1点受ける。この戦場から脱落した者は、1D6を振り、変調表の結果を適用すること。',
  369. ]
  370. ),
  371. 'MT' => DiceTable::ChainTable.new(
  372. "異形表",
  373. '1D6',
  374. [
  375. DemonSkillTableForMetamorphose.new(
  376. '1D6を振り、「妖魔忍法表A」で、ランダムに忍法の種類を決定する。妖魔化している間、その妖魔忍法を修得しているものとして扱う。この異形は、違う種類の妖魔忍法である限り、違う異形として扱う。',
  377. DEMON_SKILL_TABLES['DSA']
  378. ),
  379. DemonSkillTableForMetamorphose.new(
  380. '1D6を振り、「妖魔忍法表B」で、ランダムに忍法の種類を決定する。妖魔化している間、その妖魔忍法を修得しているものとして扱う。この異形は、違う種類の妖魔忍法である限り、違う異形として扱う。',
  381. DEMON_SKILL_TABLES['DSB']
  382. ),
  383. DemonSkillTableForMetamorphose.new(
  384. '1D6を振り、「妖魔忍法表C」で、ランダムに忍法の種類を決定する。妖魔化している間、その妖魔忍法を修得しているものとして扱う。この異形は、違う種類の妖魔忍法である限り、違う異形として扱う。',
  385. DEMON_SKILL_TABLES['DSC']
  386. ),
  387. '妖魔化している間、戦闘中、1ラウンドに使用できる忍法のコストが、自分のプロット値+3点になり、装備忍法の【揺音】を修得する。',
  388. '妖魔化している間、【接近戦攻撃】によって与える接近戦ダメージが2点になる。',
  389. '妖魔化している間、このキャラクターの攻撃に対する回避判定と、このキャラクターの奥義に対する奥義破り判定にマイナス1の修正がつく。'
  390. ]
  391. ),
  392. 'MTR' => DiceTable::Table.new(
  393. "異形表",
  394. '1D6',
  395. ['1D6を振り、「妖魔忍法表A」で、ランダムに忍法の種類を決定する。妖魔化している間、その妖魔忍法を修得しているものとして扱う。この異形は、違う種類の妖魔忍法である限り、違う異形として扱う。',
  396. '1D6を振り、「妖魔忍法表B」で、ランダムに忍法の種類を決定する。妖魔化している間、その妖魔忍法を修得しているものとして扱う。この異形は、違う種類の妖魔忍法である限り、違う異形として扱う。',
  397. '1D6を振り、「妖魔忍法表C」で、ランダムに忍法の種類を決定する。妖魔化している間、その妖魔忍法を修得しているものとして扱う。この異形は、違う種類の妖魔忍法である限り、違う異形として扱う。',
  398. '妖魔化している間、戦闘中、1ラウンドに使用できる忍法のコストが、自分のプロット値+3点になり、装備忍法の【揺音】を修得する。',
  399. '妖魔化している間、【接近戦攻撃】によって与える接近戦ダメージが2点になる。',
  400. '妖魔化している間、このキャラクターの攻撃に対する回避判定と、このキャラクターの奥義に対する奥義破り判定にマイナス1の修正がつく。']
  401. ),
  402. 'PT' => DiceTable::Table.new(
  403. 'プライズ効果表',
  404. '2D6',
  405. [
  406. '爆弾。このプライズの所持者は、行為判定にファンブルすると、1D6点の射撃戦ダメージを受ける。その後、このプライズは破壊される。ゲーム終了時に、このプライズを持っていると、功績点を1点獲得する。',
  407. '集中。そのプライズの所持者は、戦闘シーンのとき、1ラウンドに使用できる忍法のコストが1点上昇する。',
  408. '再生。そのプライズの所持者は、サイクルの終了時に、【生命力】が1点回復する。',
  409. '障壁。そのプライズの所持者は、目標値が10以上の回避判定にプラス1の修正を得る。',
  410. '加速。そのプライズの所持者は、自分が攻撃忍法を使用した時、その回避判定にマイナス1の修正を与えることができる。',
  411. '治癒。そのプライズの所持者は、ドラマシーンで回復判定を行った際、さらに【生命力】を1点回復するか、変調を1つ回復することができる。',
  412. '断絶。そのプライズの所持者は、誰かが自分を対象とした情報判定や感情判定を行おうとした時、マイナス1の修正を与えることができる。',
  413. '加護。そのプライズの所持者は、自分が集団戦ダメージを受けた時、それを射撃戦ダメージに変更することができる。',
  414. '記憶。そのプライズの所持者は、ランダムに選んだ特技1種を所持しているものとして扱う。',
  415. '業物。そのプライズの所持者は、もう1つ【接近戦攻撃】の忍法を特例修得する。その指定特技は、プライズを獲得した時に、獲得したキャラクターが設定することができる。',
  416. '呪詛。さらに2回「プライズ効果表」を振り、その2つの効果をあわせ持つ。このプライズの所持者は、サイクルの終了時に、1点の接近戦ダメージを受ける。'
  417. ]
  418. ),
  419. ## 以下流派ブック
  420. 'BNT' => DiceTable::Table.new(
  421. '戦場新効果表',
  422. '1D6',
  423. [
  424. '平地 甲:特になし。/乙:この戦場では、射撃戦の命中判定にプラス1の修正がつく。',
  425. '水中 甲:この戦場では、回避判定にマイナス2の修正がつく。/乙:この戦場では、判定でスペシャルしても【生命力】が回復する効果は発生しない。',
  426. '高所 甲:この戦場でファンブルすると接近戦ダメージを1点受ける。/乙:この戦場では、各ラウンドに使用できる忍法のコストの最大値が1減少する。',
  427. '悪天候 甲:この戦場ではすべての攻撃忍法の間合が1上昇する。/乙:この戦場では、サポート忍法の指定特技の判定にマイナス2の修正がつく。',
  428. '雑踏 甲:この戦場では、行為判定のとき、ファンブル値が1上昇する。/乙:この戦場では、奥義破り判定にマイナス1の修正がつく。',
  429. '極地 甲:ゲームマスターは、ラウンドの終わりに1D6を振る。戦闘開始時からの経過ラウンド以下の目が出ると、この戦場にいると、接近戦ダメージを1点受ける。この戦場から脱落した者は、1D6を振り、変調表の結果を適用すること。/乙:この戦場でファンブルすると集団戦ダメージを1点受ける。'
  430. ]
  431. ),
  432. 'YWT' => DiceTable::Table.new(
  433. '妖術変調対応表(現代/戦国)',
  434. '1D6',
  435. [
  436. '器術:故障(現代)/催眠(戦国)',
  437. '体術:マヒ(現代)/火達磨(戦国)',
  438. '忍術:重傷(現代)/猛毒(戦国)',
  439. '謀術:行方不明(現代)/飢餓(戦国)',
  440. '戦術:忘却(現代)/残刃(戦国)',
  441. '妖術:呪い(現代)/野望(戦国)'
  442. ]
  443. ),
  444. 'YWT1' => DiceTable::Table.new(
  445. '妖術変調対応表(現代)',
  446. '1D6',
  447. [
  448. '器術:故障',
  449. '体術:マヒ',
  450. '忍術:重傷',
  451. '謀術:行方不明',
  452. '戦術:忘却',
  453. '妖術:呪い'
  454. ]
  455. ),
  456. 'YWT2' => DiceTable::Table.new(
  457. '妖術変調対応表(戦国)',
  458. '1D6',
  459. [
  460. '器術:催眠',
  461. '体術:火達磨',
  462. '忍術:猛毒',
  463. '謀術:飢餓',
  464. '戦術:残刃',
  465. '妖術:野望'
  466. ]
  467. ),
  468. ## 誤字修正(異形態→異霊態)
  469. 'NMT' => DiceTable::ChainTable.new(
  470. "新異形表",
  471. '1D6',
  472. [
  473. DemonSkillTableForMetamorphose.new(
  474. '異霊態。「妖魔忍法表・異霊」を使用し、妖魔化している間、その妖魔忍法を修得する。', DEMON_SKILL_TABLES_NEW['DSN1']
  475. ),
  476. DemonSkillTableForMetamorphose.new(
  477. '凶身態。「妖魔忍法表・凶身」を使用し、妖魔化している間、その妖魔忍法を修得する。', DEMON_SKILL_TABLES_NEW['DSN2']
  478. ),
  479. DemonSkillTableForMetamorphose.new(
  480. '神化態。「妖魔忍法表・神化」を使用し、妖魔化している間、その妖魔忍法を修得する。', DEMON_SKILL_TABLES_NEW['DSN3']
  481. ),
  482. DemonSkillTableForMetamorphose.new(
  483. '攻激態。「妖魔忍法表・攻激」を使用し、妖魔化している間、その妖魔忍法を修得する。', DEMON_SKILL_TABLES_NEW['DSN4']
  484. ),
  485. '業魔態。妖魔化している間、戦闘中、各ラウンドに使用できる忍法のコストの合計が、自分のプロット値+3点になり、装備忍法の【揺音】(基本 p85)を修得する。',
  486. '不視態。妖魔化している間、このキャラクターの攻撃に対する回避判定と、このキャラクターの奥義に対する奥義破り判定にマイナス1の修正がつく。'
  487. ]
  488. ),
  489. 'NMTR' => DiceTable::Table.new(
  490. "新異形表",
  491. '1D6',
  492. [
  493. '異霊態。「妖魔忍法表・異霊」を使用し、妖魔化している間、その妖魔忍法を修得する。',
  494. '凶身態。「妖魔忍法表・凶身」を使用し、妖魔化している間、その妖魔忍法を修得する。',
  495. '神化態。「妖魔忍法表・神化」を使用し、妖魔化している間、その妖魔忍法を修得する。',
  496. '攻激態。「妖魔忍法表・攻激」を使用し、妖魔化している間、その妖魔忍法を修得する。',
  497. '業魔態。妖魔化している間、戦闘中、各ラウンドに使用できる忍法のコストの合計が、自分のプロット値+3点になり、装備忍法の【揺音】(基本 p85)を修得する。',
  498. '不視態。妖魔化している間、このキャラクターの攻撃に対する回避判定と、このキャラクターの奥義に対する奥義破り判定にマイナス1の修正がつく。'
  499. ]
  500. ),
  501. 'OTS' => DiceTable::Table.new(
  502. '【数奇】(御斎 p33)',
  503. '1D6',
  504. [
  505. '「兵糧丸」を一個獲得する。',
  506. '「神通丸」を一個獲得する。',
  507. '「遁甲符」を一個獲得する。',
  508. '戦場を好きな場所に変更する。',
  509. 'その戦闘の間、あらゆる判定にプラス1の修正がつく。この効果は累積しない。',
  510. 'その戦闘の間、あらゆる判定のスペシャル値が1減少する。この効果は累積しない。'
  511. ]
  512. ),
  513. 'HRPT' => DiceTable::Table.new(
  514. 'パニック表',
  515. '2D6',
  516. [
  517. 'この混乱に乗じて、勢力を拡大する者が現れる。GMは、シナリオに設定されているNPCの中から、この忍災を引き起こした者に敵対する者を一人選ぶ。そのNPCは、そのセッションの間、追加の【生命力】とそのスロットを1点獲得する。シナリオにそうしたNPCな設定されていなかった場合、この忍災を引き起こした者以外のPCの中から、ランダムにPC一人を選ぶ。そのPCはそのセッションの間、追加の【生命力】とそのスロットを1点獲得する。この効果は累積する。',
  518. 'パニックは拡大し、国際問題に発展する。日本の国益が大きく損なわれる。比良坂機関か、その下位流派に所属するPCは「功績点の獲得」のタイミングで自動的に流儀の達成に失敗したものとする。',
  519. '忍災の影響が忍びの世にも及び、この事態を引き起こした人物の責任問題に発展する。今回のセッションで【使命】(【本当の使命】がある場合はそちら)を達成出来なかったPCは「忍務失敗表」(基本 p71)を一回使用する。',
  520. '人々の間で根も葉もない噂が蔓延し、世相が暗くなる。そのセッションのドラマシーンの間、PC全員はあらゆる判定にマイナス1の修正がつく。',
  521. '忍災やパニックの犠牲者が復讐者に変わる。そのセッションのドラマシーンの間、PC全員は判定に失敗すると1点の接近戦ダメージを受ける。',
  522. '人々のパニックは暴動に発展する。そのセッションのドラマシーンの間、PC全員は判定に失敗すると1点の射撃戦ダメージを受ける。',
  523. '多くの犠牲が生まれ、人々の怒りが政府や忍者に向かう。そのセッションのドラマシーンの間、PC全員は判定に失敗すると1点の集団戦ダメージを受ける。',
  524. '人々は忍者の実在を信じ始め、その正体を探ろうとする者が現れる。そのサイクルの間、PC全員はあらゆる判定のファンブル値が1上昇する。',
  525. '上層部からしばらく大人しくしているよう厳命がくだる。そのサイクルの間、修得している攻撃忍法とサポート忍法のコストが1点上昇する(コストが「なし」のものは1になる)。',
  526. 'パニックが波及し、忍者たちは家族、友情、自信、存在意義など、それぞれ大切なものを喪失する。そのセッションの間、PC全員は、判定の結果スペシャルになっても【生命力】1点か変調を回復する効果が発生しなくなる。',
  527. '忍災の結果、PCたちに不信の目が向けられる。そのセッションに登場するキャラクターのうち、忍災を引き起こしたPCに対してプラスの【感情】を獲得している者は、その【感情】をマイナスの何かに変化する(この効果が無効化されると、元の【感情】の種類に戻る)。'
  528. ]
  529. ),
  530. 'OTAT' => DiceTable::Table.new(
  531. '覚醒表',
  532. '1D6',
  533. [
  534. '自分の力が急に恐ろしくなる。好きな覚醒済みデータを一つ選び、それを未覚醒データに変更する。',
  535. '自分の力が暴走し、周囲に被害を与える。そのシーンに登場しているキャラクター全員(自分含む)に射撃戦ダメージを1点与える。',
  536. '覚醒に伴い、身体の形が変化する。未覚醒忍法の中からランダムに一つを選び、それを覚醒済み忍法にする。',
  537. '忍者の血に目覚め、力の制御方法が理解出来るようになる。好きな未覚醒忍法を一つを選び、それを覚醒済み忍法にする。',
  538. '自分だけが操ることが出来る独自の力に目覚める。好きな未覚醒奥義一つを選び、それを覚醒済みの奥義にする。',
  539. '自分の脳に直接何かが囁きかける。集団戦ダメージを1点受けると、好きな未覚醒データの中から一つ選び、それを覚醒済みデータに変更することができる。退魔編であれば、集団戦ダメージを受ける代わりに妖魔化することで、好きな未覚醒データの中から一つ選び、それを覚醒済みデータに変更することができる。'
  540. ]
  541. ),
  542. 'ONDT' => DiceTable::Table.new(
  543. '出物表',
  544. '2D6',
  545. [
  546. '翼手 (基本 p175)/解剖刀 (隠忍 p31)',
  547. '幽命丹 (基本 p174)/魔界樹 (隠忍 p30)',
  548. '顔無の面 (基本 p174)/龍鱗 (隠忍 p30)',
  549. '落仔 (基本 p174)/蟲獲箱 (隠忍 p30)',
  550. '骨刃 (基本 p174)/魔血図 (隠忍 p30)',
  551. '死霊粉 (基本 p174)/蒼角 (隠忍 p30)',
  552. '潮満珠 (基本 p174)/屍人形 (隠忍 p30)',
  553. '生体銃 (基本 p174)/投幻香 (隠忍 p30)',
  554. '妖皮紙 (基本 p174)/渡来の干首 (隠忍 p30)',
  555. '神面瘡 (基本 p174)/眠り砂 (隠忍 p30)',
  556. '外法炉 (基本 p175)/餓鬼魂 (隠忍 p31)'
  557. ]
  558. ),
  559. ## 忍法授業シーン表(シナリオとは無関係なためこちらに記載)
  560. 'NCT1' => DiceTable::Table.new(
  561. '攻撃系忍法授業シーン表',
  562. '1D6',
  563. [
  564. "\n接近戦闘学:《刀術》《野戦術》\n【笹貫】(基本 p78)/【天道】(基本 p102)/【新理】(御斎 p34)/好きな体術\n\n御斎学園の敷地内にある森林、御斎林での授業。刃のついた近接武器のみを使って、ターゲットのベテラン教師を倒さなければならない。有利な地形で戦うこと、ターゲットの使う伝統的な技を理解することなどが重要。",
  565. "\n射撃戦闘学:《砲術》《見敵術》\n【必中】(基本 p79)/【文曲】(基本 p103)/【魔弓】(御斎 p33)/好きな器術\n\n地上十階建てから平屋まで、様々な高さの建物が並ぶ部室棟周囲で行われる。弓やスリング、拳銃、ライフルなどあらゆる武器を使って、潜伏している標的を発見、撃破を目指す。相手の移動先を予測する方法や、移動を妨げる方法なども学ぶ。",
  566. "\n集団戦闘学:《野戦術》《用兵術》\n【追撃】(基本 p80)/【伏兵】(基本 p102)/【武曲】(基本 p103)/好きな戦術\n\n御斎学園で最も高い場所のひとつ、大時計台の上で行う。地上にいる下級生に指示を出してターゲットを妨害させる。不意打ちさせる、毒を盛らせる、悪い噂を流させるなど、下級生たちを通して配下の効果的運用を知る授業。",
  567. "\n高速戦闘学:《骨法術》《意気》\n【連撃】(基本 p81)/【風饗】(基本 p81)/【噴足】(御斎 p33)/好きな忍術\n\n地下武道場での授業。一対一での素手による組み手を中心に、攻撃を当てるためにはどうすればいいのか、攻撃を仕掛けた後にどう動くことが効果的なのかなどを教わっていく。また長時間行うことで気力も試される。",
  568. "\n戦闘物理学:《仕込み》《記憶術》\n【痛打】(基本 p83)/【飢渇】(基本 p84)/【早乙女】(基本 p102)/好きな器術\n\n自身が持つ攻撃方法をより確実にする手段について学ぶ。座学を中心とした授業。武器の威力を高める、時間をかけることで標的を焦らせる、どこにいるかを把握するなどの方法を知ることができる。",
  569. "\n殺戮力学:《野戦術》《言霊術》\n【蛮歌】(基本 p82)/【共闘】(御斎 p33)/【天槍】(御斎 p33)/好きな妖術\n\n複数の班に別れて、別の班を敵対者と見なして行うグループ学習。協力しての戦い方、対象の負の感情をあおる話術に加え、地形と妖術を利用した相手を害する呪文などが講義内容に含まれる。"
  570. ]
  571. ),
  572. 'NCT2' => DiceTable::Table.new(
  573. '防御系忍法授業シーン表',
  574. '1D6',
  575. [
  576. "\n人体護身学:《衣装術》《地の利》\n【御斎魂】(基本 p102)/【衣換】(御斎 p34)/【自警】(御斎 p36)/好きな体術\n\n通常授業中に、指導教諭から攻撃を受ける。一般生徒に気付かれてはいけないため耐える方法、受け流す方法を学ぶことができる。単なる身体能力ではなく、地形や装備の利用方法を学ぶことを重視して評価される。",
  577. "\n警備防衛学:《分身の術》《暗号術》\n【かばう】(基本 p81)/【護衛】(基本 p81)/【陽動】(基本 p102)/好きな忍術\n\n広大な御斎学園の敷地全体を使った授業。指定されたターゲットの元にすぐさま赴き、授業終了時まで、護衛しなければならない。自分の動きだけでなく、護衛対象に的確な指示を出すこと、その指示を襲撃者に読み取らせないようにする方法も学習できる。",
  578. "\n特殊回避学:《手練》《地の利》\n【矢止めの術】(基本 p82)/【返し技】(基本 p82)/【身かわしの術】(基本 p83)/好きな戦術\n\n広大な大グラウンドでの授業。目隠し状態で、手裏剣、苦無、弓、拳銃やライフルといった中距離遠距離からの攻撃を受ける。単にかわすだけではなく、攻撃そのものを失敗させる、飛来物を打ち返すなど、攻撃者に対処する方法を学ぶ。",
  579. "\n忍法療法学:《対人術》《兵糧術》\n【毒飼】(基本 p81)/【仙食】(基本 p102)/【説教】(基本 p104)/好きな謀術\n\n学生寮の談話室、食堂などを使用して行う。コミュニケーションによって仲間の気力やモチベーションを回復する方法を学ぶ授業。会話のみならず、飲食物や金銭といった報酬の利用方法なども学習内容に含まれている。",
  580. "\n生存訓練学:《生存術》《意気》\n【頑健】(基本 p84)/【達人】(基本 p84)/【鋭気】(御斎 p33)/好きな体術\n\n御斎学園の所有する樹海、御斎樹海での実地授業。樹海には様々な罠が張り巡らされ、忍獣が解き放たれている。生徒たちはランダムな場所に投下され、ゴール地点を目指す。",
  581. "\n対抗忍法学:《騎乗術》《暗号術》\n【騎馬】(基本p81)/【破術】(基本p82)/【作戦指揮】(基本p83)/好きな忍術\n\n学園一の蔵書数を誇る御斎第五図書館を利用する、二人一組でチームを組み、それぞれの忍法の利用方法、対処方法を図書館で調べた後に、移動して実践を行う。相手の有利な場所をいかに避けるかも重要。"
  582. ]
  583. ),
  584. 'NCT3' => DiceTable::Table.new(
  585. '戦略系忍法授業シーン表',
  586. '1D6',
  587. [
  588. "\n情報戦略学:《記憶術》《千里眼の術》\n【占術】(基本 p82)/【暗業】(御斎 p34)/【分析】(御斎 p36)/好きな謀術\n\n生徒たちが制作した絵画が飾られた、旧校舎美術室での実習授業。絵画には怪異が関係した忍務で命を落とした生徒の伝言をはじめ、様々なメッセージが残されている。見つけだす方法、読み解く方法、その上でどう利用するかについて学習する。",
  589. "\n諜報心理学:《対人術》《伝達術》\n【感情操作】(基本p83)/【伝心】(御斎p33)/【柔気】(御斎p33)/好きな謀術\n\nコンサートなどにも利用される御斎記念音楽ホールを使用する。音楽鑑賞中の一般生徒たちの中から一人を指名され、その人物に好意を持たせたり指示を伝えたり物品を受け渡したりする実習を行う。",
  590. "\n高速機動学:《盗聴術》《異形化》\n【無拍子】(基本 p81)/【覚悟】(基本 p82)/【武曲】(基本 p104)/好きな戦術\n\n遠心力を利用した高負荷の過重力環境室において、高速機動を自分のものにするための授業を受ける。反復訓練により身体能力を拡張し、高速機動中に発生する光の屈折・分散によるプリズム効果に脳を適応させる。",
  591. "\n戦場構築学:《騎乗術》《地の利》\n【誘導】(基本 p82)/【戦場の極意】(基本 p102)/【安地】(御斎 p33)/好きな戦術\n\n自身にとって有利な地形や状況を見つけだし、戦いの場をそこに導くための方法を学ぶ。自転車、バイク、自動車、騎馬の使用をはじめ、学園内のヘリポートや輸送用列車、秘密地下通路の利用も許可されている。",
  592. "\n妨害環境学:《地の利》《封術》\n【霾天】(基本 p103)/【大火】(御斎 p34)/【氷楔】(御斎 p34)/好きな妖術\n\n大サウナ室、大食堂付属の冷凍室、強風で知られる御斎砂丘を利用して、高温や低温環境、視界を妨げる場所など、悪環境での戦い方を学ぶ授業。単なる地形や天候に留まらず、学園所属の半妖により、妖力で発生する状況も体験する。",
  593. "\n業子力学:《鳥獣術》《呪術》\n【神通力】(基本 p82)/【数奇】(御斎 p33)/【三星】(御斎 p33)/好きな妖術\n\n御斎学園専用ネットワークを使用したオンライン授業。巫女や呪術師を講師とし、人ならざるものの力を借りる、呪術を使うなどして、運命に介入し、自分にとって都合のよい方向に引き寄せる理論を学び尽くす。"
  594. ]
  595. )
  596. }.freeze
  597. # シーン表
  598. SCENE_TABLES = {
  599. ## 以下シーン表
  600. 1 'ST' => DiceTable::Table.new(
  601. 'シーン表',
  602. '2D6',
  603. [
  604. '血の臭いがあたりに充満している。何者かの戦いがあった気配。 いや?まだ戦いは続いているのだろうか?',
  605. 'これは……夢か? もう終わったはずの過去。しかし、それを忘れることはできない。',
  606. '眼下に広がる街並みを眺める。ここからなら街を一望できるが……。',
  607. '世界の終わりのような暗黒。暗闇の中、お前達は密やかに囁く。',
  608. '優しい時間が過ぎていく。影の世界のことを忘れてしまいそうだ。',
  609. '清廉な気配が漂う森の中。鳥の囀りや、そよ風が樹々を通り過ぎる音が聞こえる。',
  610. '凄まじい人混み。喧噪。影の世界のことを知らない無邪気な人々の手柄話や無駄話が騒がしい。',
  611. '強い雨が降り出す。人々は、軒を求めて、大慌てて駆けだしていく。',
  612. '大きな風が吹き荒ぶ。髪の毛や衣服が大きく揺れる。何かが起こりそうな予感……',
  613. '酔っぱらいの怒号。客引きたちの呼び声。女たちの嬌声。いつもの繁華街の一幕だが。',
  614. '太陽の微笑みがあなたを包み込む。影の世界の住人には、あまりにまぶしすぎる。',
  615. ]
  616. ),
  617. 'CST' => DiceTable::Table.new(
  618. '都市シーン表',
  619. '2D6',
  620. [
  621. 'シャワーを浴び、浴槽に疲れた身体を沈める。時には、癒しも必要だ。',
  622. '閑静な住宅街。忍びの世とは関係のない日常が広がっているようにも見えるが……それも錯覚なのかもしれない',
  623. '橋の上にたたずむ。川の対岸を結ぶ境界点。さて、どちらに行くべきか……?',
  624. '人気のない公園。野良猫が一匹、遠くからあなたを見つめているような気がする。',
  625. '至福の一杯。この一杯のために生きている……って、いつも言ってるような気がするなぁ。',
  626. '無機質な感じのするオフィスビル。それは、まるで都市の墓標のようだ。',
  627. '古びた劇場。照明は落ち、あなたたちのほかに観客の姿は見えないが……。',
  628. '商店街を歩く。人ごみに混じって、不穏な気配もちらほら感じるが……。',
  629. 'ビルの谷間を飛び移る。この街のどこかに、「アレ」は存在するはずなのだが……。',
  630. '見知らぬ天井。いつの間にか眠っていたのだろうか?それにしてもここはどこだ?',
  631. '廃屋。床には乱雑に壊れた調度品や器具が転がっている。',
  632. ]
  633. ),
  634. 'MST' => DiceTable::Table.new(
  635. '館シーン表',
  636. '2D6',
  637. [
  638. 'どことも知れぬ暗闇の中。忍びの者たちが潜むには、おあつらえ向きの場所である。',
  639. '洋館の屋根の上。ここからなら、館の周りを一望できるが……。',
  640. '美しい庭園。丹精こめて育てられたであろう色とりどりの花。そして、綺麗に刈り込まれた生垣が広がっている。',
  641. 'あなたは階段でふと足を止めた。何者かの足音が近づいているようだ。',
  642. 'あなたに割り当てられた寝室。ベッドは柔らかく、調度品も高級なものばかりだが……。',
  643. 'エントランスホール。古い柱時計の時報が響く中、館の主の肖像画が、あなたを見下ろしている。',
  644. '食堂。染み一つないテーブルクロスに覆われた長い食卓。その上は年代物の燭台や花で飾られている。',
  645. '長い廊下の途中。この屋敷は広すぎて、迷子になってしまいそうだ。',
  646. '戯れに遊戯室へ入ってみた。そこには撞球台やダーツの的、何組かのトランプが散らばっているポーカーテーブルがあった。',
  647. 'かび臭い図書室。歴代の館の主たちの記録や、古今東西の名著が、ぎっしりと棚に並べられている。',
  648. '一族の納骨堂がある。冷気と瘴気に満ちたその場所に、奇妙な叫びが届く。遠くの鳥のさえずりか?それとも死者の恨みの声か……?',
  649. ]
  650. ),
  651. 'DST' => DiceTable::Table.new(
  652. '出島シーン表',
  653. '2D6',
  654. [
  655. '迷宮街。いつから囚われてしまったのだろう?何重にも交差し、曲がりくねった道を歩き続ける。このシーンの登場人物は《記憶術》で判定を行わなければならない。成功すると、迷宮の果てで好きな忍具を一つ獲得する。失敗すると、行方不明の変調を受ける。',
  656. '幻影城。訪れた者の過去や未来の風景を見せる場所。このシーンの登場人物は、《意気》の判定を行うことができる。成功すると、自分の持っている【感情】を好きな何かに変更することができる。',
  657. '死者たちの行進。無念の死を遂げた者たちが、仲間を求めて彷徨らっている。このシーンの登場人物は《死霊術》で判定を行わなければならない。失敗すると、ランダムに変調を一つを受ける。',
  658. 'スラム。かろうじて生き延びている人たちが肩を寄せ合い生きているようだ。ここなら辛うじて安心できるかも……。',
  659. '落書きだらけのホテル。その周囲には肌を露出させた女や男たちが、媚態を浮かべながら立ち並んでいる。',
  660. '立ち並ぶ廃墟。その影から、人とも怪物ともつかぬ者の影が、あなたの様子をじっとうかがっている。',
  661. '薄汚い路地裏。巨大な黒犬が何かを貪っている。あなたの気配を感じて黒犬は去るが、そこに遺されていたのは……。',
  662. '昏い酒場。バーテンが無言でグラスを磨き続けている。あなたの他に客の気配はないが……。',
  663. '地面を覆う無数の瓦礫。その隙間から暗黒の瘴気が立ち昇る。このシーンの登場人物は《生存術》で判定を行わなければならない。失敗すると、好きな【生命力】を1点失う。',
  664. '熱気溢れる市場。武器や薬物などを売っているようだ。商人たちの中には、渡来人の姿もある。このシーンの登場人物は、《経済力》で判定を行うことができる。成功すると、好きな忍具を一つ獲得できる。',
  665. '目の前に渡来人が現れる。渡来人はあなたに興味を持ち、襲い掛かってくる。このシーンの登場人物は《刀術》で判定を行わなければならない。成功すると、渡来人を倒し、好きな忍具を一つ獲得する。失敗すると、3点の接近戦ダメージを受ける。',
  666. ]
  667. ),
  668. 'TST' => DiceTable::Table.new(
  669. 'トラブルシーン表',
  670. '2D6',
  671. [
  672. '同行者とケンカしてしまう。うーん、気まずい雰囲気。',
  673. 'バシャ! 同行者のミスでずぶ濡れになってしまう。……冷たい。',
  674. '敵の気配に身を隠す。……すると、同行者の携帯が着信音を奏で始める。「……えへへへへ」じゃない!',
  675. '同行者の空気の読めない一言。場が盛大に凍り付く。まずい。何とかしないと。',
  676. '危機一髪! 同行者を死神の魔手から救い出す。……ここも油断できないな。',
  677. '同行者が行方不明になる。アイツめ、どこへ逃げたッ!',
  678. 'ずて────ん! あいたたたた……同行者がつまずいたせいで、巻き込まれて転んでしまった。',
  679. '同行者のせいで、迷子になってしまう。困った。どこへ行くべきか。',
  680. '「どこに目つけてんだ、てめぇ!」同行者がチンピラにからまれる。うーん、助けに入るべきか。',
  681. '! 油断していたら、同行者に自分の恥ずかしい姿を見られてしまう。……一生の不覚!',
  682. '同行者が不意に涙を流す。……一体、どうしたんだろう?',
  683. ]
  684. ),
  685. 'NST' => DiceTable::Table.new(
  686. '日常シーン表',
  687. '2D6',
  688. [
  689. 'っくしゅん! ……うーん、風邪ひいたかなあ。お見舞いに来てくれたんだ。ありがとう。',
  690. '目の前のアイツは、見違えるほどドレスアップしていた。……ゆっくりと大人な時間が過ぎていく。',
  691. 'おいしそうなスイーツを食べることになる。たまには甘いものを食べて息抜き息抜き♪',
  692. 'ふわわわわ、いつの間にか寝ていたようだ。……って、あれ? お前、いつからそこにいたッ!!',
  693. '買い物帰りの友人と出会う。方向が同じなので、しばらく一緒に歩いていると、思わず会話が盛り上がる。',
  694. 'コンビニ。商品に手を伸ばしたら、同時にその商品をとろうとした別の人物と手が触れあう。なんという偶然!',
  695. 'みんなで食卓を囲むことになる。鍋にしようか? それとも焼き肉? お好み焼きなんかもい〜な〜♪',
  696. 'どこからか楽しそうな歌声が聞こえてくる。……って、あれ? 何でお前がこんなところに?',
  697. '野良猫に餌をやる。……猫はのどを鳴らし、すっかりあなたに甘えているようだ。',
  698. '「……! ……? ……♪」テレビは、なにやら楽しげな場面を映している。あら。もう、こんな時間か。',
  699. '面白そうなゲーム! 誰かと対戦することになる。GMは、「戦術」からランダムに特技1つを選ぶ。このシーンに登場しているキャラクターは、その特技の判定を行う。成功した場合、同じシーンに登場しているキャラクターを1人を選び、そのキャラクターの自分に対する【感情】を好きなものに変更する(何の【感情】も持っていない場合、好きな【感情】を芽生えさせる)。',
  700. ]
  701. ),
  702. 'TKST' => DiceTable::Table.new(
  703. '東京シーン表',
  704. '2D6',
  705. [
  706. 'お台場、臨界副都心。デート中のカップルや観光客が溢れている。',
  707. '靖国神社。東京の中とも思えぬ、緑で満ちた場所だ。今は観光客もおらず、奇妙に静かだ……。',
  708. '東京大学の本部キャンパス。正門から伸びる銀杏並木の道を学生や教職員がのんびりと歩いている。道の向こうには安田講堂が見える。',
  709. '山手線の中。乗車率200%を超える、殺人的な通勤ラッシュ真っ最中。この中でできることは限られている……。',
  710. '霞が関。この場に集う情報は、忍者にとっても価値が高いものだ。道を行く人々の中にも、役人や警察官が目につく。',
  711. '渋谷駅前の雑踏。大型屋外ヴィジョンが見下ろす中で、大勢の若者たちが行き交っている。',
  712. '夜の新宿歌舞伎町。酔っぱらったサラリーマン、華やかな夜の蝶、明らかに筋ものと判る男、外国人などの様々な人間と、どこか危険な雰囲気に満ちている。',
  713. '新宿都庁。摩天楼が林立するビル街の下、背広姿の人々が行き交う。',
  714. '神田古書街。多くの古書店が軒を連ねている。軒先に積まれた本の山にさえ、追い求める謎や、深遠な知識が埋もれていそうな気がする。',
  715. '山谷のドヤ街。日雇い労働者が集う管理宿泊施設の多いこの場所は、身を隠すにはうってつけだ。',
  716. '東京スカイツリーの上。この場所からならば東京の町が一望できる。',
  717. ]
  718. ),
  719. 'KST' => DiceTable::Table.new(
  720. '回想シーン表',
  721. '2D6',
  722. [
  723. '闇に蔓延する忍びの気配。あのときもそうだった。手痛い失敗の記憶。今度こそ、うまくやってみせる。',
  724. '甘い口づけ。激しい抱擁。悲しげな瞳……一夜の過ちが思い返される。',
  725. '記憶の中でゆらめくセピア色の風景。……見覚えがある。そう、私はここに来たことがあるはずだッ!!',
  726. '目の前に横たわる死体。地面に広がっていく。あれは、私のせいだったのだろうか……?',
  727. 'アイツとの大切な約束を思い出す。守るべきだった約束。果たせなかった約束。',
  728. '助けを求める右手が、あなたに向かってまっすぐ伸びる。あなたは、必死でその手を掴もうとするが、あと一歩のところで、その手を掴み損ねる……。',
  729. 'きらきらと輝く笑顔。今はもう喪ってしまった、大事だったアイツの笑顔。',
  730. '恐るべき一撃! もう少しで命を落とすところだった……。しかし、あの技はいまだ見切れていない。',
  731. '幼い頃の記憶。仲の良かったあの子。そういえば、あの子は、どこに行ってしまったのだろう。もしかして……。',
  732. '「……ッ!!」激しい口論。ひどい別れ方をしてしまった。あんなことになると分かっていたら……。',
  733. '懐の中のお守りを握りしめる。アイツにもらった、大切な思い出の品。「兵糧丸」を1つ獲得する。',
  734. ]
  735. ),
  736. 'GST' => DiceTable::Table.new(
  737. '戦国シーン表',
  738. '2D6',
  739. [
  740. '炎上する山城。人々の悲鳴や怒号がこだましている。どうやら、敵対する武将による焼き討ちらしい。今ならば、あるいは……。',
  741. '荒れ果てた村。カラスの不吉な鳴き声が聞こえてくる中で、やせ細った村人たちが、うつろな瞳でこちらを伺っている。',
  742. '人気のない山道。ただ鳥の声だけが響いている。通りがかった人を襲うのには、好都合かもしれない。',
  743. '乾いた骸の転がる合戦後。生き物の姿はなく、草の一本さえも生えていない。落ち武者たちの恨みがましい声が聞こえてきそうだ……。',
  744. '不気味な気配漂う森の中。何か得体のしれぬものが潜んでいそうだ。',
  745. '荒れ果てた廃寺。ネズミがカサカサと這いまわる本堂の中を、残された本尊が見下ろしている。',
  746. '街道沿いの宿場町。戦から逃げてきたらしい町人や、商売の種を探す商人、目つきの鋭い武士などが行き交い、賑わっている。',
  747. '城の天守閣のさらに上。強く吹く風が、雲を流していく。',
  748. '館の天井裏。この下では今、何が行われているのか……。',
  749. '合戦場に設けられた陣内。かがり火がたかれ、武者たちが酒宴を行っている。',
  750. '戦の真っただ中にある合戦場。騎馬にまたがった鎧武者が駆け抜けていく。勝者となるのは、いずれの陣営だろうか。',
  751. ]
  752. ),
  753. 'GAST' => DiceTable::Table.new(
  754. '学校シーン表',
  755. '2D6',
  756. [
  757. '清廉な気配が漂う森の中。鳥のさえずりやそよ風が木々を通りすぎる音が聞こえる。',
  758. '学校のトイレ。……なんだか少しだけ怖い気がする。',
  759. '誰もいない体育館。バスケットボールがころころと転がっている。',
  760. '校舎の屋上。一陣の風が吹き、衣服をたなびかせる。',
  761. '校庭。体操服姿の生徒たちが走っている。',
  762. '廊下。休憩時間か放課後か。生徒たちが、楽しそうにはしゃいでいる。',
  763. '学食のカフェテリア。生徒たちがまばらに席につき、思い思い談笑している。',
  764. '静かな授業中の風景。しかし、忍術を使って一般生徒に気取られない会話をしている忍者たちもいる。',
  765. '校舎と校舎をつなぐ渡り廊下。あなた以外の気配はないが……。',
  766. '特別教室。音楽室や理科室にいるのってなんか楽しいよね。',
  767. 'プール。水面が、ゆらゆら揺れている。',
  768. ]
  769. ),
  770. 'KYST' => DiceTable::Table.new(
  771. '京都シーン表',
  772. '2D6',
  773. [
  774. '夜の街並み。神社仏閣はライトアップされ、にぎやかな酔客が通りを埋める。昼間とはまた違った景色が広がっている。',
  775. '京都駅ビル。その屋上は、京都市で最も高く、周囲を一望できる。',
  776. '旅館で一休み。……のはずが、四方山話に花が咲く。',
  777. '鴨川のあたりを歩いている。カップルが均等に距離を置いて座っているのが面白い。',
  778. '京都はどこにでもおみやげ物屋があるなぁ。さて、あいつに何を買ってやるべきか……?',
  779. '「神社仏閣シーン表(JBST)」で決定。',
  780. '新京極でお買い物。アーケードには、新旧様々な店が建ち並ぶ。',
  781. '大学が近くにあるのかな? 安い定食屋や古本屋、ゲームセンターなどが軒を連ねる学生街。京都はたくさん大学があるなぁ。',
  782. '静かな竹林。凛とした気配が漂う。',
  783. '祇園。時折、しずしずと歩く舞妓さんとすれ違う。雰囲気のある町並みだ。',
  784. '一般公開された京都御所の中を歩く。昼間だというのに人通りはあまりなく、何だか少し寂しい気持ち。',
  785. ]
  786. ),
  787. 'JBST' => DiceTable::Table.new(
  788. '神社仏閣シーン表',
  789. '2D6',
  790. [
  791. '清明神社。一条戻り橋を越えたところにある小さな社。陰陽師に憧れる女性たちの姿が目立つ。',
  792. '東寺。東寺真言宗総本山。密教独特の厳しい気配が漂う。',
  793. '平安神宮。大鳥居を白無垢の花嫁行列がくぐり抜けていくのが見える。どうやら結婚式のようだ。',
  794. '慈照寺――通称、銀閣寺。室町後期の東山文化を代表する建築である。錦鏡池を囲む庭園には、物思いにふける観光客の姿が……。',
  795. '鹿苑寺――通称、金閣寺。室町前期の北山文化を代表する建築である。鏡湖池に映る逆さ金閣には、強力な「魔」を封印していると言うが……?',
  796. '三十三間堂。荘厳な本堂に立ち並ぶ千一体の千手観音像は圧巻。',
  797. '清水寺。清水坂を越え、仁王門を抜けると、本堂――いわゆる清水の舞台にたどり着く。そこからは、音羽の滝や子安塔が見える。',
  798. '八坂神社。祇園さんの名前で知られるにぎやかな神社。舞妓さんの姿もちらほら。',
  799. '伏見稲荷。全国約四万社の稲荷神社の総本宮。稲荷山に向かって立ち並ぶ約一万基の鳥居は、まるで異界へと続いているかのようだ……。',
  800. '化野念仏寺。無数の石塔、石仏が立ち並ぶ景色は、どこか荒涼としている……。',
  801. '六道珍皇寺。小野篁が冥界に通ったとされる井戸のある寺。この辺りは「六道の辻」と呼ばれ、不思議な伝説が数多く残っている。',
  802. ]
  803. ),
  804. 'AKST' => DiceTable::Table.new(
  805. '秋空に雪舞えばシーン表',
  806. '2D6',
  807. [
  808. 'どこから紛れ込んできたのか。シーンプレイヤーが1D6を振って3以下ならナタを持った少女、4以上なら冬篭りに備えた熊が襲ってくる。シーンに登場したキャラクターは、少女なら《刀術》・熊なら《鳥獣術》で判定し、失敗すると接近戦ダメージを1点受ける。',
  809. '3:暗い夜の森の中、月明かりのみが周囲を照らす。忍が動くにはいい時間だ。',
  810. '4:秋晴れの下、両脇で黄金色の稲穂が風に靡く道。刈り取りを控えたこの短い間にしか見る事の出来ない貴重な光景だ。',
  811. '5:美味しそうな果実がたわわに実っている。一つくらい取って行ってもバチは当たらないだろう…。',
  812. '6:山中に続く林道。勾配の厳しい道から、紅葉が浮かび流れる穏やかな川が見下ろせる。',
  813. '7:村の広場。山や田畑が一望できる。波打つ稲穂の絨毯、山々には紅葉。秋を感じるひと時だ。',
  814. '8:パチパチと爆ぜる音。どうやら籾殻で焚き火をしているらしい。少し暖まっていこうか。',
  815. '9:神秘的な神社。祭りの準備が進められているが、今は人がいないようだ。',
  816. 'ひと雨きそうな午後。重たい空気にキンモクセイがつと香る。',
  817. '草に埋もれ、崩れかけの古い空き家。どこか物悲しさを感じる。',
  818. 'カツーン、カツーン、誰かが丑の刻参りをしている音が聞こえる。シーンに登場したキャラクターは《呪術》で判定し、成功すると誰かに《呪い》の変調を与えることができる。失敗すると《呪い》の変調を受ける。',
  819. ]
  820. ),
  821. 'CLST' => DiceTable::Table.new(
  822. '災厄シーン表',
  823. '1D6',
  824. [
  825. '瘴気に晒され続けたことであなたの身体が妖魔へと変貌する。《封術》の判定に失敗したシーンプレイヤーは、背景:劣勢因子と背景:魔人を獲得する。',
  826. '妖魔があなたに従属を強いる。やつが掲げた手の中には…。《遁走術》の判定に失敗したシーンプレイヤーは、背景:人質と兵糧丸1つを獲得する。',
  827. '妖魔の群れに捕まった!独力での包囲網突破のために君の体は限界を迎えようとしていた。《拷問術》の判定に失敗したシーンプレイヤーは、背景:侵食と神通丸1つを獲得する。',
  828. '戦いの激化はあなたの体を蝕む。《医術》の判定に失敗したシーンプレイヤーは、背景:病魔と神通丸1つを獲得する。',
  829. '下級妖魔を束ねたボスが、新たなる力を手に入れようとしている。シーンプレイヤーが《見敵術》の判定に失敗した場合、ボスに対してエニグマ:『秘奥義』が公開状態で追加される。',
  830. '力なき者が生き残ることは出来ない。ボスが新たな力を手に入れようとしている。シーンプレイヤーが《怪力》の判定に失敗した場合、ボスに対してエニグマ:『八面六臂』が公開状態で追加される。',
  831. ]
  832. ),
  833. 'DXST' => DiceTable::Table.new(
  834. '出島EXシーン表',
  835. '2D6',
  836. [
  837. '迷宮街。いつから囚われてしまったのだろう?何重にも交差し、曲がりくねった道を歩き続ける。このシーンの登場人物は《記憶術》で判定を行わなければならない。成功すると、迷宮の果てで好きな忍具を一つ獲得する。失敗すると、行方不明の変調を受ける。',
  838. '幻影城。訪れた者の過去や未来の風景を見せる場所。このシーンの登場人物は、《意気》の判定を行うことができる。成功すると、自分の持っている【感情】を好きな何かに変更することができる。',
  839. '死者たちの行進。無念の死を遂げた者たちが、仲間を求めて彷徨らっている。このシーンの登場人物は《死霊術》で判定を行わなければならない。失敗すると、ランダムに変調を一つを受ける。',
  840. 'スラム。かろうじて生き延びている人たちが肩を寄せ合い生きているようだ。ここなら辛うじて安心できるかも……。',
  841. '落書きだらけのホテル。その周囲には肌を露出させた女や男たちが、媚態を浮かべながら立ち並んでいる。',
  842. '立ちふさがるのは妖魔の群れ。他に道などない、真正面から突き進むほかは…災厄シーン表(CLST)を振ること。',
  843. '薄汚い路地裏。巨大な黒犬が何かを貪っている。あなたの気配を感じて黒犬は去るが、そこに遺されていたのは……。',
  844. '昏い酒場。バーテンが無言でグラスを磨き続けている。あなたの他に客の気配はないが……。',
  845. '地面を覆う無数の瓦礫。その隙間から暗黒の瘴気が立ち昇る。このシーンの登場人物は《生存術》で判定を行わなければならない。失敗すると、好きな【生命力】を1点失う。',
  846. '熱気溢れる市場。武器や薬物などを売っているようだ。商人たちの中には、渡来人の姿もある。このシーンの登場人物は、《経済力》で判定を行うことができる。成功すると、好きな忍具を一つ獲得できる。',
  847. '目の前に渡来人が現れる。渡来人はあなたに興味を持ち、襲い掛かってくる。このシーンの登場人物は《刀術》で判定を行わなければならない。成功すると、渡来人を倒し、好きな忍具を一つ獲得する。失敗すると、3点の接近戦ダメージを受ける。',
  848. ]
  849. ),
  850. 'HC' => DiceTable::Table.new(
  851. '中忍試験シーン表',
  852. '2D6',
  853. [
  854. '深い闇が辺りを覆う。何度目かの夜……いつまでこの試験は続くのだろう。このシーンに登場するキャラクターは《生存術》で判定を行い、失敗すると集団戦ダメージを1点受ける。',
  855. '山の冷気が肉体を蝕む。このシーンに登場するキャラクターは《衣装術》で判定を行い、失敗すると射撃戦ダメージを1受ける。',
  856. '腹を空かせた獣が襲いかかってくる。このシーンに登場するキャラクターは、《鳥獣術》で判定を行い、失敗すると射撃戦ダメージを1点受ける。',
  857. '上忍の仕掛けたトラップが発動。このシーンに登場するキャラクターは《罠術》で判定を行い、失敗すると射撃戦ダメージを1点受ける。',
  858. '濃い霧が出てきた。視界が極端に悪くなり、不安を感じる……。',
  859. '清廉な気配が漂う森の中。鳥のさえずりや、そよ風が木々を通り過ぎる音が聞こえる。',
  860. '朽ちた山小屋を発見する。何年も使った様子はなさそうだが……。',
  861. '山の天気は変わりやすい。嵐がやってくる。今後、戦闘が発生したとき、戦場表を使わなかった場合、その戦場は「平地」ではなく「悪天候」として扱う。',
  862. 'ひときわ高くなっている尾根にたどり着く。このシーンの登場するキャラクターは、《登術》で判定を行い、成功すると、好きなキャラクター1人の【居所】を獲得する。',
  863. '深山幽谷(しんざんゆうこく)の果てに、清涼な泉を発見する。ふう、生き返るな。このシーンに登場するキャラクターは、《意気》の判定に成功すると、【生命力】を1点回復させることができる。',
  864. '脱落した別のグループの忍者の死体を発見する。こいつらには、もう不要だろう。好きな忍具1つを獲得する。(何を獲得するか宣言すること)。',
  865. ]
  866. ),
  867. 'HK' => DiceTable::Table.new(
  868. '影の街でシーン表',
  869. '2D6',
  870. [
  871. '血の臭いがあたりに充満している。何者かの戦いがあった気配。 いや?まだ戦いは続いているのだろうか?',
  872. 'これは……夢か? もう終わったはずの過去。しかし、それを忘れることはできない。',
  873. '眼下に広がる街並みを眺める。ここからなら街を一望できるが……。',
  874. '世界の終わりのような暗黒。暗闇の中、お前達は密やかに囁く。',
  875. '死者たちの行進。無念の死を遂げた者たちが、死者を求めて彷徨っている。このシーンの登場人物は《死霊術》で判定を行わなければいけない。失敗すると、ランダムに変調1つを受ける。',
  876. '立ち並ぶ廃墟。その影から、人とも怪物ともつかない者の影が、あなたの様子を窺っている。',
  877. '地面を覆う瓦礫。その隙間から暗黒の瘴気が立ち昇る。このシーンの登場人物は、《生存術》で判定を行わなければならない。失敗すると好きな【生命力】1点を失う。',
  878. '強い雨が降り出す。人々は、軒を求めて、大慌てて駆けだしていく。',
  879. '大きな風が吹き荒ぶ。髪の毛や衣服が大きく揺れる。何かが起こりそうな予感……',
  880. '酔っぱらいの怒号。客引きたちの呼び声。女たちの嬌声。いつもの繁華街の一幕だが。',
  881. '太陽の微笑みがあなたを包み込む。影の世界の住人には、あまりにまぶしすぎる。',
  882. ]
  883. ),
  884. 'HLST' => DiceTable::Table.new(
  885. '斜歯ラボシーン表',
  886. '2D6',
  887. [
  888. '今週のびっくりどっくり斜歯開発室、1D6を振り奇数なら好きな忍具が入手できる。偶数でも好きな忍具が入手できるが、射撃戦ダメージを1点受ける。',
  889. 'トランスポーターだ!《絡繰術》で判定すること。失敗するとどこかへ飛ばされて《行方不明》の変調を受ける。成功した場合、望む場所へ到達できる。好きな「居所」を入手すること。',
  890. '改造室。調整途中の下忍戦闘員たちが錯乱し、あなたに襲い掛かる。〈傀儡術〉の判定を行う。失敗すると1点の集団戦ダメージを受ける。成功すれば「居所」を持っている他のキャラクターに1点の集団戦ダメージを与えることができる。',
  891. 'エレベーター。ただし四方八方へ移動する。行き先ボタンは無い。この箱はこれから何処へ行くのか。',
  892. '長く続く廊下。不気味なほどに静まり返っているが、周囲からはまとわりつくような敵意を感じる。',
  893. 'たくさんの巨大な円筒状のガラスが立ち並び、中には様々な人間が謎の液体に浮かぶ。もちろん肝心な部分は光の反射で見えない。こいつは…まさか…!培養プラントシーン表(PLST)を振ること。',
  894. 'LEDが視覚的にやかましいコンピュータールーム。壁一面を埋めるディスプレイがちかちか光る。斜歯の誇る超コンピュータは性能に反して古めかしい。',
  895. '司令室。とうとうDr.斜歯を追い詰めた。泣いて土下座するDr.斜歯……の首がバネ仕掛けで飛び出し、大爆発。影武者だ!このシーン中のファンブル値は+2される。',
  896. '斜歯のロボット兵器がところ狭しと並べられている。こいつらが起動したとしたら…《潜伏術》で判定し、失敗した場合ロボット兵器に見つかって1点の射撃戦ダメージを受ける。',
  897. '自爆装置のある中枢ルーム。《火術》で判定し、成功すると自爆させることができる。自爆させた場合、Dr.斜歯に2点の接近戦ダメージを与えることができる。',
  898. '部屋に置かれた実験装置によりマインドコントロールを受けてしまう。このシーンのあなたはGMの指定した行動をとらねばならない。',
  899. ]
  900. ),
  901. 'HM' => DiceTable::Table.new(
  902. '密室シーン表',
  903. '2D6',
  904. [
  905. '……ふう。あいつらと一緒にいると、緊張で息苦しくなる。トイレにいるときだけは、少しだけ落ち着くな。',
  906. 'パチ、パチパチ……。電灯が明滅する。ずっと薄暗い部屋にいたせいで、時間の感覚が麻痺してきた。一体、いまは何時なんだ?',
  907. 'ガチャン!誰かが食器を落として割ってしまったようだ。落としたヤツは悪びれもせず、こっちを見て肩をすくめている。',
  908. '誰かがつけたテレビ。くだらないバラエティ番組が映っている。静かな部屋に作り物の笑いがむなしく響く。',
  909. '空調がイカれているのか、妙に暑い。じっとりと汗ばんでくる……。',
  910. 'ぴちょん、ぴちょん、ぴちょん……静かな室内に水道から水が滴る音が響く。さっき、きっちり閉めたはずなんだが。',
  911. 'タバコの煙が目に染みる。閉じきった部屋で吸うから、空気が悪くなってきているな。',
  912. '床に散乱した書類の中から、一枚の写真を見つける。この部屋の持ち主と、その恋人らしき人物が仲よさそうに写っているが……。',
  913. '誰かが、八つ当たり気味に壁を殴る。そんなことして、一体なんになるというのだろう?',
  914. 'ベッドでごろんと横になる。くそ!いつになったら、ここから出られるんだ!',
  915. '壁のシミをぼんやりとながめていたら、それがゆっくりと人の顔の形になり、にやりと笑いかけてきた。……幻覚か。',
  916. ]
  917. ),
  918. 'HO' => DiceTable::Table.new(
  919. '病院シーン表',
  920. '2D6',
  921. [
  922. '謎の入院患者。車椅子に座った少女が、あなたをじっと見つめている。',
  923. '急患入り口。サイレンの音に続いて、ストレッチャーに乗せられた救急患者が運ばれてきた。',
  924. '病院の屋上。巨大な病院の敷地が一望できる。',
  925. '診察室。机と清潔なベットが設えられている無機室な部屋。机の上にはパソコンといくつかの器具が置かれている。',
  926. '病院の廊下。患者の姿はなく、静まり返っている。',
  927. '面会用のロビーは、入院患者とその見舞客で賑わっている。だが、それに紛れて、妙な気配を感じるが……。',
  928. '病室。きつい消毒液の香りに混じって、死の匂いが漂っている。',
  929. '奇妙な囁き声。「助けてくれ……。」そんな訴えを耳元で聞いた気がしたが……?',
  930. 'ナースステーション。数人の看護師たちが慌ただしく業務をこなしている。',
  931. '中庭。どこからか悲鳴が聞こえたような気がするが……?',
  932. '霊安室。その扉が並ぶ長い廊下には、地下特有の淀んだ空気が漂っている。なぜだか気分が悪い。',
  933. ]
  934. ),
  935. 'HR' => DiceTable::Table.new(
  936. '龍動シーン表',
  937. '2D6',
  938. [
  939. '血の匂いが辺りに充満している。何者かの戦いがあった気配。いや?まだ戦いは続いているのだろうか?',
  940. 'これは……夢か?もう終わったはずの過去。しかし、それを忘れることはできない。',
  941. '眼下に広がる街並みを眺める。ここからなら街を一望できるが……。',
  942. '世界の終りのような暗闇。暗闇の中、お前たちは囁く。',
  943. '雰囲気のある古い街並みを歩く。あの建物は見たことがあるような……。',
  944. '霧の中を黒い影が飛び回っている。連中か?',
  945. '分厚い霧が街を折っている。霧の向こうには黒い影が……。',
  946. '強い雨が降り出す。人々は軒を求めて、大慌てで駆け出していく。',
  947. '大きな風が吹き荒ぶ。髪の毛や衣服が大きく揺れる。何かが起こりそうな予感……。',
  948. 'どこからか奇妙な歌が響く。それはまるで、邪悪な神に捧げる祈りのようにも聞こえた。',
  949. '無残で冒涜的な死体。犠牲者の表情は苦悶に満ちあふれ、四肢には何者かに貪り食われた痕がある。',
  950. ]
  951. ),
  952. 'HS' => DiceTable::Table.new(
  953. '催眠シーン表',
  954. '1D6',
  955. [
  956. 'あなたは心地よいベッドの中で、恋人の肌のぬくもりを感じながら微睡んでいる。恋人は「そろそろ起きる時間」とベッドからすり抜ける。目を開けると、そこには裸のナビキャラクターがいた。そして、ナビキャラクターはあなたに優しく口づけをした。柔らかな感触が、あなたの記憶を掘り起こす。',
  957. 'あなたは一人で死体の片付けを行っている。とても恐ろしく、とても憎かったナビキャラクターを殺したのだ。ナビキャラクターの意志のない瞳を見下ろし、あなたは晴れやかな気分になる。そして、その死体の手のひらに何かが書かれているのに気が付いた。',
  958. 'あなたはなぜかTVショーに登場している。黒いサングラスをかけた司会者と楽しくおしゃべりしていたら、友人を紹介してほしいと言われ、電話を渡された。覚えのある番号にかけてみると、受話器の向こうからナビキャラクターの声がした。声は、あなたにこう囁く……。',
  959. 'あなたはいつの間にか子どもになって、お気に入りのアニメを見ている。夢中になってアニメを見ていると、ナビキャラクターがアニメの登場人物として現れた。ナビキャラクターは、画面から抜け出してきて、あなたをアニメの世界に引きずり込む。そして、あなたは世界の真実に気付いてしまう!',
  960. 'あなたはレストランでお腹を空かせている。そこに給仕の姿をしたナビキャラクターが、食事を運んできた。メインディッシュの銀製の蓋を開けてみると、そこにはあなたの大好物が。食欲をそそる香りが立ちこめ、あなたは重大な事実を思い出す。',
  961. 'あなたは膨大な数の書架が林立する無人の図書館を歩いている。何気なく一冊の本を棚から抜き出すと、その本の向こう側にナビキャラクターの顔がのぞいている。「お前の求めるものは、その本の14ページに書かれている。」その言葉に従い、恐る恐る14ページを開いてみると……。',
  962. ]
  963. ),
  964. 'HT' => DiceTable::Table.new(
  965. '滅びの塔シーン表',
  966. '2D6',
  967. [
  968. '血の臭いがあたりに充満している。何者かの戦いがあった気配。 いや?まだ戦いは続いているのだろうか?',
  969. 'これは……夢か? もう終わったはずの過去。しかし、それを忘れることはできない。',
  970. '眼下に広がる街並みを眺める。ここからなら街を一望できるが……。',
  971. '世界の終わりのような暗黒。暗闇の中、お前達は密やかに囁く。',
  972. '優しい時間が過ぎていく。影の世界のことを忘れてしまいそうだ。',
  973. '凄まじい業火。このシーンの登場する者は、『器術』分野からランダムに特技1つを選び、判定を行う。失敗すると射撃戦ダメージ1点を受ける。',
  974. '凄まじい人混み。喧噪。影の世界のことを知らない無邪気な人々の手柄話や無駄話が騒がしい。',
  975. '強い雨が降り出す。人々は、軒を求めて、大慌てて駆けだしていく。',
  976. '大きな風が吹き荒ぶ。髪の毛や衣服が大きく揺れる。何かが起こりそうな予感……',
  977. '凄まじい業火。このシーンの登場する者は、『器術』分野からランダムに特技1つを選び、判定を行う。失敗すると射撃戦ダメージ1点を受ける。',
  978. '太陽の微笑みがあなたを包み込む。影の世界の住人には、あまりにまぶしすぎる。',
  979. ]
  980. ),
  981. 'HY' => DiceTable::Table.new(
  982. '夜行列車シーン表',
  983. '2D6',
  984. [
  985. '車内の灯りがすべて消える。停電か?それとも……。すべてが闇に覆われる。',
  986. 'どうやらこの車輌は喫煙席のようだ。もうもうと煙がたちこめている。しかし、あなたたち以外に、客の姿は見えないのだが……?',
  987. '気分を変えるために、食堂車に移動する。そこには「解体屋」を名乗る例の女性がいた。あなたにむかって、婉然とほほえみかけてくる。',
  988. '……はッ!?夢か?いつの間にか眠っていたようだ。何か、悪夢を見ていたようなのだが……。',
  989. '窓越しに通過する駅のホームが見える。しかし、その駅の名前をどうしても読むことができない。どうにも、日本語には見えないのだが……。',
  990. 'ガタンガタンガタン……路線を走る音をぼんやりと聞いている。一体、この列車はどこに向かっているんだろう?',
  991. '車内を照らす白熱灯に、羽虫がたかり、それに合わせるように光が明滅する。',
  992. '髑髏のような細身の車掌あなたのチケットを確認すると、にたりと邪悪に微笑み、去って行った。',
  993. '一等車輛はコンパートメントになっているようだ。コンパートメントの中からは、楽しげな親子の話し声が聞こえてくるが……?',
  994. '「お弁当に、お茶……。」車内販売の少女がやってくる。しかし、そこで売られている食べ物や飲み物は、生き物の内臓のような器官やぐねぐねと蠢く触手、異様な毛の塊など異形のものばかり。《経済力》の判定に成功すると、好きな「忍具」1つを購入できる。',
  995. '車輌の果てを確かめるため、延々扉をくぐっているが、いつまでたっても最前列(最後尾?)にたどりつかない。今、いったい何輌目だろうか?',
  996. ]
  997. ),
  998. 'NTST' => DiceTable::Table.new(
  999. '夏の終わりシーン表',
  1000. '2D6',
  1001. [
  1002. 'どこから紛れ込んできたのか。ナタを持った少女がこちらに迫ってくる。あっそぼうよぉ。シーンに登場したキャラクターは《刀術》で判定し、失敗すると接近戦ダメージを1点受ける。',
  1003. '暗い夜の森の中、月明かりのみが周囲を照らす。忍が動くにはいい時間だ。',
  1004. '鬱蒼と繁っていて少し涼しい森の中。ほんのひとときでもいい。使命を忘れて少し涼もうか。',
  1005. 'ほとんど人が出入りしない公民館。かろうじて扇風機は回っているが暑い。',
  1006. '山の斜面に立ち並ぶ墓石。踏み固められた周囲と墓前に供えられた小さな花束。こんな山中にも日々通う人がいるのだろうか。',
  1007. '村の広場。田畑が一望できる。夏の風物詩であるセミの鳴き声がうるさい。',
  1008. '澄み切った清流。冷たい飛沫が気持ちいい。森の中の穴場だ。',
  1009. '神秘的な神社。夏の終わりに向けて祭りの準備がされているが、今は人がいないようだ。',
  1010. '無人の廃屋が並び、不気味な雰囲気が漂う。廃屋の影から息を潜める何者かの気配を感じる。',
  1011. '村の上空。ここから眺めれば村など小さいものだ。',
  1012. 'カツーン、カツーン、誰かが丑の刻参りをしている音が聞こえる。シーンに登場したキャラクターは《呪術》で判定し、成功すると誰かに《呪い》の変調を与えることができる。失敗すると《呪い》の変調を受ける。',
  1013. ]
  1014. ),
  1015. 'PLST' => DiceTable::Table.new(
  1016. '培養プラントシーン表',
  1017. '1D6',
  1018. [
  1019. '培養槽。あなたそっくりの人間が謎の液体に浸かっている。あなたは本当に本物のあなただろうか?《記憶術》で判定を行い、失敗すると《忘却》の変調を受ける。',
  1020. '巨大なガラス管の中に冒涜的な生物が蠢く実験室。《意気》で判定を行い、失敗すると《マヒ》の変調を受ける。',
  1021. '試験管に浮かぶDr斜歯のクローン脳が大量にあるクローン施設。',
  1022. '各流派頭領が浮かぶ試験管。ランダムな特技を決定し判定を行う。決定した特技が自分の得意分野の場合、成功すると兵糧丸を1つ入手する。得意分野でない場合、失敗すると接近戦ダメージを1点受ける。',
  1023. '無人の実験室。中央には破壊された培養器があり、人とも獣ともつかない濡れた足跡が扉へと続いている。',
  1024. '美少年改造プラント。このシーンに登場した者は《変装術》で判定すること。成功した場合、美少年になることができる。',
  1025. ]
  1026. ),
  1027. ## 以下正忍記
  1028. 'TMT' => DiceTable::Table.new(
  1029. '魔都東京シーン表',
  1030. '2D6',
  1031. [
  1032. 'お台場。臨海副都心。テレビ局や展示場など、特徴的な建造物は冒涜的な改造を施されている。',
  1033. '靖国神社。東京の中とも思えぬ緑で満ちたその場所には、妖魔の姿も見えない。結界か何かだろうか。',
  1034. '東京大学の本郷キャンパス。多数の机を積み重ねたバリケードと有刺鉄線によって門は塞がれている。',
  1035. '山手線の線路の上。今はここを走る電車も存在しない。代わりに蠢く何かはいるようだが。',
  1036. '霞が関。行政機関が集う、日本の中枢。しかし、そこは既に機能しておらず、妖魔の跳梁を許している。',
  1037. '渋谷駅前。ひび割れて何も映していない大型野外ビジョンにざざ、とノイズが走る。',
  1038. '夜の新宿歌舞伎町。東洋一の繁華街であるこの場所は、魔都と化した今でも盛況である。',
  1039. '新宿都庁。摩天楼の林立するビル街の下、忍者たちが妖魔と戦っているのが見える。',
  1040. '神田古書街。多くの古書店が軒を連ねている。そこに並ぶ本には魔書と呼ばれるものも多数存在しているようだ。',
  1041. '町田駅前。都心から離れたここなら東京の外と繋がっているかもしれない。',
  1042. '電波塔の上。ここからなら変貌してしまった魔都東京の姿を一望できる。そしてそれは、妖魔たちからも見つけられやすいということだ。',
  1043. ]
  1044. ),
  1045. 'TMG' => DiceTable::Table.new(
  1046. '魔都学園シーン表',
  1047. '2D6',
  1048. [
  1049. '瘴気が漂う森の中。時折怒号や叫び声が聞こえてくるが、それもやがて静かになる。',
  1050. '学校のトイレ。…個室から何本も手が伸びている。',
  1051. '誰もいない体育館。コロコロと転がっているのは人の首なのか?',
  1052. '校舎の屋上。禍々しい髑髏が並べられ、その口からは霧状の何かが吐き出している。',
  1053. '校庭。逃げ惑う生徒の姿が見える。',
  1054. '廊下。作られたバリケードを緩慢な動きの妖魔が崩そうとしている。',
  1055. '学食のカフェテリア。ぶちまけられた食べ物が散乱している。',
  1056. '静かな授業中の風景はすでにない。教室に残る人々の顔には焦りや不安が張り付いている。',
  1057. '校舎と校舎を繋ぐ渡り廊下。あなた以外の気配はないが…油断はできない。',
  1058. '特別教室。音楽室や理科室に籠る人々は皆、肩を寄せ合って震えている。',
  1059. 'プール。ゆらゆらと揺れる水面の下に蠢く何かの姿が見える。',
  1060. ]
  1061. ),
  1062. 'TC' => DiceTable::Table.new(
  1063. 'カジノシーン表',
  1064. '2D6',
  1065. [
  1066. 'カジノのトイレ。窓から逃げる奴がいるんだ。ここを張っておかないわけにはいくまい。',
  1067. '控室。運営の為の黒服や料理人といった裏方が控えている。綺羅びやかなとは程遠い、陰鬱とした空気。',
  1068. '港。絢爛な光や音を背中に、華やかと対局にいる君たちが佇む。',
  1069. 'VIPルーム。権力者や資産家が密談をする中、君たちもまた潜む。',
  1070. 'カジノの中。人間の欲望を手招きする中、思惑という名の影が走る。',
  1071. 'カジノに併設される静謐なバー。この雰囲気を壊すような野暮な真似はしないだろう?',
  1072. 'カジノに併設されている風俗街。蠱惑的な女性が、君たちを誘う。',
  1073. 'バカラテーブル。カジノで最も高い金が動くとされるギャンブル。カードをしぼる手に、汗が滴る、鉄火場',
  1074. 'スロットゲーム。脳を麻痺させる絢爛な音が鳴り響く。',
  1075. 'リラクゼーション施設。マッサージやエステ、スパといった施設が立ち並ぶ。',
  1076. 'ジャックポット!人生を変える幸運の一撃。羨望、渇望、あらゆる嫉妬の視線が君に集まる。君はチップを一つ獲得する。',
  1077. ]
  1078. ),
  1079. 'TGS' => DiceTable::Table.new(
  1080. '月天に死の咲くシーン表',
  1081. '2D6',
  1082. [
  1083. '何者かの強い恨みと悪意を感じる。焼き鏝を押されたかのような激痛が走る。《呪術》で判定を行う。失敗すると接近戦ダメージ1点を受けるとともに「花印」を一つ刻まれる。',
  1084. '目の前に、七色に光る楽園のような光景が広がっている。頭の中で継承が鳴るも、なぜか、思わずそちらに足をむけてしまう。《幻術》で判定を行う。失敗すると射撃戦ダメージを1点受けると共に、「花印」を一つ刻まれる。',
  1085. 'どこからか不思議な声が聞こえる。透き通るようなその声に、全てをゆだねたくなる……。《言霊術》で判定を行う。失敗すると、「花印」を一つ刻まれる。',
  1086. 'さあっと風が吹き、木々が揺れ、さわさわと葉が触れ合う。まるで、こちらを見ながらひそひそと会話をしているかのようだ。',
  1087. '視線を感じる。振り向いても、そこには一凛の花があるのみだ。',
  1088. '一息つこうと上がり込んだ建物で丸薬を見つけた。悪いが、使えるものは使わせてもらおう。兵糧丸を一つ獲得する。',
  1089. '潜んでいた人影が、月明かりの下に現れる。自分以外のPCを一人だけシーンに登場させる。',
  1090. '村人に出会い、忍具を渡される。お礼を言うために顔を上げると、そこには死体があるのみだった。「神通丸」を一つ獲得する。',
  1091. '忍具の符が貼られているのを見つける。この村全体を使い、封印か結界でも張っていたのだろうか……。どのみち、この様ではもう用済みだろう。「遁甲符」を一つ獲得する。',
  1092. '調査中、ふと、神棚に奉られた酒に目が行く。吸い寄せられるようにそれを手に取り、一息に飲み干す。身体が火照り、完備な香りが鼻の奥から少し抜ける。「花印」が一つ消える。',
  1093. '手を引かれたような気がする。その感覚に従って歩くと、隠された細い道を見つけた。これは、村に張り巡らされた隠し通路……?《地の利》で判定を行う。成功すると、このシーンの直後に追加で自身のドラマシーンを一つ獲得する。',
  1094. ]
  1095. ),
  1096. 'TRM' => DiceTable::Table.new(
  1097. 'ロードムービーシーン表',
  1098. '2D6',
  1099. [
  1100. '調達した車に乗って距離を稼ぐ。ラジオから電車の爆発事故のニュースが流れる。目撃者の証言として、PCたちの特徴が語られている……。',
  1101. 'どうしても、人混みを避けることができない。蝙蝠が来るといけない。せめて変装して紛れるとしよう。',
  1102. '無理をしたのか、少し調子が悪い。そのせいか、ちょっとしたことでイライラしてしまいそうだ。',
  1103. '人目を避け、森の中を行く。木々が揺れる音や虫の鳴き声が聞こえてくる。どこかから美味しそうな香りが漂ってくる。',
  1104. 'ここらで少し食事をとるのも悪くないかもしれない……。',
  1105. '土砂降りの雨が、体温を奪う。どこか休める場所があるといいのだが……。以降、メインフェイズに戦闘が発生した場合、その戦場が「悪天候」になる。',
  1106. '上空を蝙蝠が飛んでいたような気がする。敵の襲撃に気を配らねば……。',
  1107. 'どこかから流れてくる音楽。聞き覚えがある。あれは、いつのことだったろうか……。',
  1108. '道が二つに分かれている。さて、どちらに行くべきか……?',
  1109. 'これは……夢か?もう終わったはずの過去。しかし、それを忘れることはできない。',
  1110. '潮風が香る。海が見えてきた。波は一定のリズムで岸壁にぶつかり、白く砕けて飛び散っていく。',
  1111. ]
  1112. ),
  1113. 'TMC' => DiceTable::Table.new(
  1114. 'マスカレイド・キャッスルシーン表',
  1115. '2D6',
  1116. [
  1117. '庭園には周囲と調和した見事な噴水がある。その水路は湖に通じているようだ。',
  1118. '地下牢に囚人は入っていないし、看守もいない。長い間使われていないようだ。歴史的価値で残されているのだろう。',
  1119. '立派な蔵書が並ぶ広い客間。着飾った文化人たちが活発な議論を戦わせている。部屋には酒の匂いが漂っている。',
  1120. '遊戯室の中央ではビリヤードやポーカーが行われており、隅ではバーテンが客の望みに応じてカクテルを作っている。',
  1121. '大広間では立食パーティーが常時開催されており、人が絶える事はない。あちこちに有名人や政治家らしき姿が見える。',
  1122. '城の中央に位置する、この城の名物である二重螺旋階段。登りと降り、二つの階段が絡み合う見事な設計となっている。',
  1123. '電灯が消えた廊下を行き交う召使いは蝋台を手にしている。城主の好みだろうか、 この城には電化されていない箇所が多い。',
  1124. 'ダンスホールでは楽団がゆったりとした音楽を奏で続けている。人々は踊りと休みを繰り返しながらそれぞれ楽しんでいるようだ。',
  1125. '吹き抜ける風が心地良いバルコニー。軽食が用意され、来場客が談笑しながら食事を楽しんでいる。',
  1126. '時計塔は古式で、据え付けられた時計は 歯車とネジで作られたものだが、驚くほど正確に時を刻んでいる',
  1127. '屋根の上はとても静かで、真下で行われている狂騒が嘘のようだ。こんなところに登って来るのは暇を持て余した忍者ぐらいだ。',
  1128. ]
  1129. ),
  1130. 'TKG' => DiceTable::Table.new(
  1131. '学校シーン表(黒星祭)',
  1132. '2D6',
  1133. [
  1134. '清廉な気配が漂う森の中。鳥のさえずりやそよ風が木々を通りすぎる音が聞こえる。',
  1135. '学校のトイレ。……なんだか少しだけ怖い気がする。',
  1136. '体育館。多くの観客が、ステージの上で行われているパフォーマンスに夢中になっている。中には、暗いことをいいことに秘密の会話をするものも。',
  1137. '校舎の屋上。一陣の風が吹き、衣服をたなびかせる。',
  1138. '模擬店が多数出展している校庭。誰かの視線に振り向くと、あなたに話しかけようと、機会を伺っている生徒の姿が……。',
  1139. '廊下。休憩時間か放課後か。生徒たちが、楽しそうにはしゃいでいる。',
  1140. '学校のカフェテリア。多くの生徒たちが、フランクフルトやたこ焼き、クレープやチュロスなど、生徒たちがつくった食べ物に興じている。',
  1141. '静かな授業中の風景。しかし、忍術を使って一般生徒に気取られない会話をしている忍者たちもいる。',
  1142. '模擬店となった教室。メイド喫茶やお化け屋敷など、教室ごとに思い思いの出し物で盛り上がっているようだ。',
  1143. '特別教室。音楽室や理科室にいるのってなんか楽しいよね。',
  1144. 'プール。水面が、ゆらゆら揺れている。',
  1145. ]
  1146. ),
  1147. 'TKH' => DiceTable::Table.new(
  1148. '恋人との日々シーン表',
  1149. '2D6',
  1150. [
  1151. 'アカリの部屋にやってきた。 彼女は小さく笑いながらも、あなたを快く 迎えてくれる。',
  1152. '些細なことで喧嘩してしまった。 暫く互いに口を聞かずに過ごしているが、 アカリはどこかバツの悪そうな表情をしている。',
  1153. 'アカリが料理を振る舞ってくれた。 アカリの料理の腕は如何ほどだろうか。 考えを巡らせるあなたの目前で、鍋の蓋がぼわんと湯気を出して開く。',
  1154. '映画館にやってきた。 ホラー映画に恋愛映画にアクション映画。 明かりが落ち、映像を見つめる二人の手がそっと触れ合う。',
  1155. '図書館にやってきた。 来るやいなや、 アカリはもくもくと、静かにページをめくっている。 彼女はどんな本を読むのだろうか。',
  1156. '森林浴にやってきた。 森の木漏れ日が作る影が、 アカリの頬に落ちている。',
  1157. '繁華街にやってきた。 楽しいものや美味しいもので満たされたこの場所に、彼女はいつになく上機嫌だ。',
  1158. '遊園地にやってきた。 あれこれとアトラクションを探してあなたの手を引くアカリは、いつもより子供っぽく見えた。',
  1159. 'アカリとカフェでお茶を楽しんでいる。 目の前に座る彼女のいたずらっぽい微笑みが、 あなたの気持ちを和らげる。',
  1160. 'アカリとゲームを楽しんでいる。 アカリがあなたに対戦しようと持ちかけてきた。どうやら秘策があるようだが?',
  1161. 'あなたの部屋にやってきた。 あなたが忍者であることを感づかれないように、その足跡を覆い隠す。ついでに彼女に見てほしくないものも。',
  1162. ]
  1163. ),
  1164. ## 以下流派ブック
  1165. 'OTFK' => DiceTable::Table.new(
  1166. '不良高校シーン表',
  1167. '2D6',
  1168. [
  1169. '誰かが教室に猫を連れてきた!泣く子も黙るC組の生徒といえど、猫の愛らしい表情には釘付けだ。',
  1170. '校庭の端にある体育倉庫は、どんなことをするにもぴったりの場所だ。誰かを呼び出して締め上げるにしろ、忍者同士の秘密の会話に勤しむにしろ。',
  1171. '夜の倉庫街。すでに人通りはなく、明かりといえばオレンジ色にちらつく街灯だけだ。',
  1172. '下校時間の校庭。不良生徒たちを見ては、ひそひそと話す生徒たちの姿がちらりと見える。教職員ですら、こちらを見ても眉をひそめてただ通り過ぎるだけだ。',
  1173. '夕方の校舎裏は昼間の教室では味わえない静寂に包まれている。湿ったコンクリート越しに聞こえるものといったら、カラスの鳴き声と、サッカー部の練習の掛け声ぐらいだ。',
  1174. '荒れ放題の教室。キャッチボールに興じる生徒に喧嘩を始める生徒まで。騒ぎ声は一日中止むことはない。',
  1175. '教室の前の廊下に、割れた窓ガラスが散乱している。吹きざらしになった窓の外からは冷たい風が吹き付けていた。',
  1176. '通学路沿いにある橋の下。橋の上を電車が通るたびに、けたたましい線路の音が響き渡る。',
  1177. '昼休みの食堂。人混みにまみれるここだけは、C組も他の生徒も関係ない。',
  1178. '高校近くにある河原の土手で、草の上に寝転がって雲を眺める。どこかで響く吹奏楽の練習の音と、風の音とともに、穏やかな時間が流れていく。',
  1179. '他校の不良生徒からの襲撃だ!校庭に集まった奴らは、釘バットを手に、C組の生徒を出せと騒ぎ立てている。'
  1180. ]
  1181. ),
  1182. }.freeze
  1183. 71 register_prefix(RTT.prefixes.map { |k| "\\d*#{k}" }, TABLES.keys.map { |k| "\\d*#{k}" }, SCENE_TABLES.keys.map { |k| "\\d*#{k}" }, DEMON_SKILL_TABLES.keys.map { |k| "\\d*#{k}" }, DEMON_SKILL_TABLES_NEW.keys.map { |k| "\\d*#{k}" })
  1184. end
  1185. end
  1186. end

lib/bcdice/game_system/Shiranui.rb

100.0% lines covered

100.0% branches covered

58 relevant lines. 58 lines covered and 0 lines missed.
19 total branches, 19 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Shiranui < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Shiranui'
  7. # ゲームシステム名
  8. 1 NAME = '不知火'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'しらぬい'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~HELP
  13. ■∞D66ダイスロール
  14. 「 ∞D66 」または「 ID66 」
  15. ( ID は Infinite D の略です)
  16. □行動力や攻撃力の指定
  17. 「 x+∞D66 」または「 x+ID66 」
  18. ( x は行動力や攻撃力)
  19. □鬼火の使用について
  20. 鬼火を使用する∞D66は、ダイスボットでサポートしていません。
  21. ■おみくじを引く
  22. OMKJ
  23. HELP
  24. 1 INFINITE_D66_ROLL_REG = /^((\d+)\+)?(∞|I)D66$/i.freeze
  25. 1 register_prefix('(\d+\+)?(∞|I)D66')
  26. 1 def initialize(command)
  27. 15 super(command)
  28. 15 @sort_barabara_dice = true
  29. end
  30. 1 def eval_game_system_specific_command(command)
  31. 15 then: 12 if (m = INFINITE_D66_ROLL_REG.match(command))
  32. 12 then: 5 else: 7 fixed_score = m[1]&.to_i
  33. 12 roll_infinite_d66(fixed_score)
  34. else: 3 else
  35. 3 roll_tables(command, TABLES)
  36. end
  37. end
  38. 1 def roll_infinite_d66(fixed_score)
  39. 12 steps = []
  40. 12 while steps.empty? || steps.last.to_continue_diceroll?
  41. body: 20 # 個別の出目をあつかうので、 roll_d66 ではなく roll_barabara を使う
  42. 20 dices = @randomizer.roll_barabara(2, 6).sort
  43. 20 steps << InifiniteD66Step.new(dices)
  44. end
  45. 12 is_failure = steps.first.score.zero? # 「しくじり」か?
  46. 12 then: 2 else: 10 total = is_failure ? 0 : steps.sum(&:score) + fixed_score.to_i
  47. 12 result_text = "(#{self.class.make_command_text(fixed_score)})"
  48. 12 result_text += " > " + steps.map(&:to_s).join(' > ')
  49. 12 then: 2 if is_failure
  50. 2 result_text += " > しくじり"
  51. else: 10 else
  52. 10 then: 7 else: 3 result_text += " > " + self.class.score_expression_text(steps, fixed_score) if steps.size > 1 || !fixed_score.nil?
  53. 10 result_text += " > " + total.to_s
  54. end
  55. 12 Result.new(result_text).tap do |r|
  56. 12 r.critical = steps.size > 1
  57. 12 r.failure = is_failure
  58. 12 r.fumble = is_failure
  59. end
  60. end
  61. 1 def self.make_command_text(fixed_score)
  62. 12 then: 7 else: 5 fixed_score.nil? ? "∞D66" : "#{fixed_score}+∞D66"
  63. end
  64. 1 def self.score_expression_text(steps, fixed_score)
  65. 7 text = steps.map(&:score).join('+')
  66. 7 else: 3 then: 4 text = "#{fixed_score}+(#{text})" unless fixed_score.nil?
  67. 7 text
  68. end
  69. 1 class InifiniteD66Step
  70. 1 def initialize(dices)
  71. 20 @dices = dices.dup.freeze
  72. end
  73. 1 def score
  74. 45 if repdigit?
  75. # ゾロ目の場合
  76. then: 28
  77. 28 digit = @dices.first
  78. 28 if digit == 1
  79. then: 6 # 1 のゾロ目なら 0 となる
  80. 6 0
  81. else
  82. else: 22 # 1 以外のゾロ目なら、数字の 10 倍となる
  83. 22 digit * 10
  84. end
  85. else
  86. else: 17 # ゾロ目でない場合は、 D66 様式で値を算出する
  87. 17 @dices[0] * 10 + @dices[1]
  88. end
  89. end
  90. 1 def repdigit?
  91. 65 @dices[0] == @dices[1]
  92. end
  93. # ダイスロールを継続する必要があるか?
  94. 1 def to_continue_diceroll?
  95. 20 repdigit? && @dices[0] != 1
  96. end
  97. 1 def to_s
  98. 20 "[#{@dices[0]},#{@dices[1]}]"
  99. end
  100. end
  101. TABLES = {
  102. 1 "OMKJ" => DiceTable::Table.new(
  103. "おみくじ",
  104. "1D6",
  105. [
  106. "大凶[御利益1]――このみくじにあたる人は、凶運から逃れることができぬ者なり。まさに凶運にその身をゆだねてこそ、浮かぶ瀬もあれ。……これより上演中に演者が振る[∞D66]で初めて⚀⚀が出たら、御利益を使っても振り直しができない。",
  107. "凶[御利益2]――このみくじにあたる人は、吉兆を逃す定めにある。まさに、天の与うるを取らざれば反ってその咎めを受く。……これより上演中に演者が振る[∞D66]で初めて⚅⚅が出たら、強制的に1回の振り直しをする。",
  108. "小吉[御利益3]――このみくじにあたる人は、神使の機嫌を損ねている。神使が何に怒り、何に苛立っているのかは、まさに神のみぞ知る。……神使の機嫌が突然、悪くなる。これより上演中に神使は何かと理由をつけてはシラヌイの前から立ち去ろうとする。",
  109. "中吉[御利益4]――このみくじにあたる人は、神使の機嫌を良くすることを行った者なり。神使が何に喜び、なぜ機嫌が良いのか、まさに神のみぞ知る。……神使の機嫌がすこぶる良くなる。これより上演中に神使は上機嫌となり、シラヌイに何かにつけて話しかけてくれる。",
  110. "吉[御利益5]――このみくじにあたる人は、悪運を幸運へと変える道を進む者なり。まさに禍福は糾える縄の如し。……これより上演中に演者が振る[∞D66]で初めて⚀⚀が出たら、御利益を消費することなく、1回の振り直しをする。",
  111. "大吉[御利益6]――このみくじにあたる人は、思いもよらぬ幸運に巡り合う者なり。まさに、暗き道より出て、気づけば月の光あり。……これより上演中に演者が振る[∞D66]で1回だけ、サイコロの出目を⚅⚅に変えてよい。",
  112. ]
  113. ),
  114. }.freeze
  115. 1 register_prefix(TABLES.keys)
  116. end
  117. end
  118. end

lib/bcdice/game_system/ShoujoTenrankai.rb

100.0% lines covered

75.0% branches covered

31 relevant lines. 31 lines covered and 0 lines missed.
8 total branches, 6 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class ShoujoTenrankai < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'ShoujoTenrankai'
  7. # ゲームシステム名
  8. 1 NAME = '少女展爛会TRPG'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'しようしよてんらんかいTRPG'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. 出来事表:
  14. ・季節
  15.  SPRING 春/SUMMER 夏/AUTUMN 秋/WINTER 冬
  16. ・時刻
  17.  MORNING 朝/NOON 昼/AFTERNOON 昼下がり/
  18.  TWILIGHT 黄昏/NIGHT 夜中/MIDNIGHT 夜更け
  19. ・棲み処
  20.  NORBLE 貴族趣味/MARCHEN メルヒェン/COLONIAL コロニアル/
  21.  SHELF 本棚のある場所/LITTLE 小さな妹の部屋/
  22.  ELDER 素敵なお姉さまの部屋/ATERIEL アトリエ/OPEN 集まれる場所/
  23.  HAUNTED 精神的瑕疵物件/SIMPLE 侘び住まい
  24. ・いろいろな場所
  25.  LARGE 広い場所/CORRIDOR 廊下/STAIRS 階段/
  26.  COSY 居心地のいい場所/TERRACE テラス・ベランダ/
  27.  GARRET 屋根裏/KITCHEN 台所/BATH 浴室/REST 化粧室/
  28.  CELLER 地下倉庫/LUMBER 物置/GARDEN 庭園/WASTED 廃園/
  29.  RUIN 廃屋/SHORE 水のほとり
  30. MESSAGETEXT
  31. 1 register_prefix("SPRING", "SUMMER", "AUTUMN", "WINTER", "MORNING", "NOON", "AFTERNOON", "TWILIGHT", "NIGHT", "MIDNIGHT", "NORBLE", "MARCHEN", "COLONIAL", "SHELF", "LITTLE", "ELDER", "ATERIEL", "OPEN", "HAUNTED", "SIMPLE", "LARGE", "CORRIDOR", "STAIRS", "COSY", "TERRACE", "GARRET", "KITCHEN", "BATH", "REST", "CELLER", "LUMBER", "GARDEN", "WASTED", "RUIN", "SHORE")
  32. 1 def eval_game_system_specific_command(command)
  33. 153 info = self.class::EVENT_TABLES[command]
  34. 153 then: 0 else: 153 return nil if info.nil?
  35. 153 name = info[:name]
  36. 153 table = info[:table]
  37. 153 text, number1, number2 = getEventTableResult(table)
  38. 153 tensionText = getTensionText(number1, number2)
  39. 153 result = "出来事表:#{name}([#{number1},#{number2}]) > #{text}#{tensionText}"
  40. 153 return result
  41. end
  42. 1 def getTensionText(number1, number2)
  43. 153 diff = (number1 - number2).abs
  44. 153 then: 124 else: 29 return "" if diff == 0
  45. 29 return "(テンション+#{diff})"
  46. end
  47. 1 def getEventTableResult(table)
  48. 153 number1 = @randomizer.roll_once(6)
  49. 153 number2 = @randomizer.roll_once(6)
  50. 153 isOdd = number1.even?
  51. 153 index = number2 - 1
  52. 153 then: 90 else: 63 index += 6 if isOdd
  53. 153 text = table[index]
  54. 153 then: 0 else: 153 return nil if text.nil?
  55. 153 return text, number1, number2
  56. end
  57. EVENT_TABLES =
  58. {
  59. 1 "SPRING" => {
  60. name: "春",
  61. table: [
  62. '【奇・1】【花びら(純従)】(グッズ)が舞い込んで来ます。蝶だったかもしれません。',
  63. '【奇・2】【初めて見る花(純察)】(グッズ)が咲いています。',
  64. '【奇・3】春の香りがふと、強くただよいます。(ロマンティック+1)',
  65. '【奇・4】春の嵐が窓を打ち付けています。(ルナティック+1)',
  66. '【奇・5】鳥のさえずりが聞こえてきます。',
  67. '【奇・6】軽く汗ばむほどの陽気です。',
  68. '【偶・1】春霞がぼんやりと景色を包み込んでいます。(カタストロフ+1)',
  69. '【偶・2】花が散りました。',
  70. '【偶・3】しんしんと花冷えがします。',
  71. '【偶・4】春の雨が銀の紗をかけた様にさらさらと降っています。',
  72. '【偶・5】開け放した窓のカーテンを春風がやさしく揺らしています。(ハートフル+1)',
  73. '【偶・6】気持ちよさそうにしている生き物(【コンパニオン】から任意)がいます。'
  74. ],
  75. },
  76. "SUMMER" => {
  77. name: "夏",
  78. table: [
  79. '【奇・1】建物の中に蔓草が入り込んでいます。(カタストロフ+1)',
  80. '【奇・2】大きな虹がかかっています。(ハートフル+1)',
  81. '【奇・3】稲妻が空を裂きます。',
  82. '【奇・4】むくむくの入道雲が遠くに見えます。',
  83. '【奇・5】虫の声が辺りを満たしています。',
  84. '【奇・6】激しい嵐が屋敷を揺すっています。(ロマンティック+1)',
  85. '【偶・1】雲の影がゆっくりと庭を横切っていきます。',
  86. '【偶・2】【夏の花(支純)】(グッズ)が咲き誇っています。',
  87. '【偶・3】風もなく、ひどく蒸し暑い日です。',
  88. '【偶・4】虫が一生懸命動き回っています。',
  89. '【偶・5】物陰からふと、涼しい風が吹いてきました。',
  90. '【偶・6】焼け付く日差しの中、黒々とした影が落ちています。(ルナティック+1)'
  91. ],
  92. },
  93. "AUTUMN" => {
  94. name: "秋",
  95. table: [
  96. '【奇・1】たわわに実った果物があります。',
  97. '【奇・2】鳥の声が鋭く響き渡ります。(カタストロフ+1)',
  98. '【奇・3】芯の冷えた木枯らしが通り過ぎていきます。',
  99. '【奇・4】鬱々と長い秋の雨が降り続いています。',
  100. '【奇・5】空が不思議に紫がかって見えます。',
  101. '【奇・6】木々が鮮やかな色に染まっています。',
  102. '【偶・1】【秋の花(従純)】(グッズ)がひと群れになって咲いています。',
  103. '【偶・2】見事な夕焼けが辺り一面を染め上げます。(ロマンティック+1)',
  104. '【偶・3】ぱたりと物音がやみ、しんと静まりかえります。(ルナティック+1)',
  105. '【偶・4】吸い込まれるような青い空が高く広がっています。(ハートフル+1)',
  106. '【偶・5】【初めて見る木の実(純察)】(グッズ)が転がっています。',
  107. '【偶・6】【枯葉(従純)】(グッズ)がさくさく、さらさらと音を立てます。'
  108. ],
  109. },
  110. "WINTER" => {
  111. name: "冬",
  112. table: [
  113. '【奇・1】太陽(月)に暈がかかっています。',
  114. '【奇・2】風花が舞っています。',
  115. '【奇・3】雪が積もっています。',
  116. '【奇・4】恐ろしい勢いの吹雪が屋敷を埋めていきます。(ルナティック+1)',
  117. '【奇・5】おだやかな小春日和です。(ハートフル+1)',
  118. '【奇・6】霙がぽしゃぽしゃと降っています。',
  119. '【偶・1】冬の空と空気が、硝子のように張り詰めています。',
  120. '【偶・2】薪を焚く暖かな匂いがただよっています。(ロマンティック+1)',
  121. '【偶・3】窓硝子が曇っています。',
  122. '【偶・4】【冬の花(従支)】(グッズ)が凛と咲いています。',
  123. '【偶・5】氷柱(霜柱、氷)が鋭い光を投げかけています。',
  124. '【偶・6】骸骨のようにそびえる冬の木の枝に、そこだけ青々とヤドリギが茂っています。(カタストロフ+1)'
  125. ],
  126. },
  127. "MORNING" => {
  128. name: "朝",
  129. table: [
  130. '【奇・1】起きたら涙を流していました。',
  131. '【奇・2】眠ったのとは別の場所で目覚めました。(ルナティック+1)',
  132. '【奇・3】寝相が悪かったのか、痛い思いをして目覚めました。(ハートフル+1)',
  133. '【奇・4】朝露が輝いています。',
  134. '【奇・5】見事な朝焼けになりました。',
  135. '【奇・6】まだかなり眠気が残っています。(ロマンティック+1)',
  136. '【偶・1】むやみに爽快な気分です。',
  137. '【偶・2】なんだか体がこわばっていて、くたびれた感じがします。(カタストロフ+1)',
  138. '【偶・3】ひどく喉が渇いています。',
  139. '【偶・4】白い月がまだ空に残っています。',
  140. '【偶・5】最後の星が朝の光に飲み込まれる瞬間を見ました。',
  141. '【偶・6】鳥の声が響いています。'
  142. ],
  143. },
  144. "NOON" => {
  145. name: "昼",
  146. table: [
  147. '【奇・1】なんだかじっとしていられません。',
  148. '【奇・2】奇妙なだるさを感じています。',
  149. '【奇・3】ひどくお腹がすいています。',
  150. '【奇・4】急に厚い雲が日差しを遮りました。',
  151. '【奇・5】薄い雲の向こうに、オパールの円盤のような太陽があります。(ロマンティック+1)',
  152. '【奇・6】なんだか無性にいらいらします。',
  153. '【偶・1】この世界に自分ひとりだけが取り残されたような気分に襲われました。(ルナティック+1)',
  154. '【偶・2】変に草木の緑が目に付きます。(カタストロフ+1)',
  155. '【偶・3】なんだか急に、寒気を感じました。',
  156. '【偶・4】さっぱりやる気が起きません。',
  157. '【偶・5】みんなで賑やかに遊んでいる声が聞こえてきます。',
  158. '【偶・6】目に触れるあらゆるものが輝いて見えます。(ハートフル+1)'
  159. ],
  160. },
  161. "AFTERNOON" => {
  162. name: "昼下がり",
  163. table: [
  164. '【奇・1】快い眠気に襲われています。',
  165. '【奇・2】まだ食べ足りない感じがします。',
  166. '【奇・3】急に天気雨が降り出しました。(ロマンティック+1)',
  167. '【奇・4】雲の隙間から輝く光の矢が降り注いでいます。',
  168. '【奇・5】どこかから甘い匂いが漂ってきます。',
  169. '【奇・6】なんとはなしに物憂く、昼の日差しが憂鬱です。(ルナティック+1)',
  170. '【偶・1】元気が有り余っている感じがします。',
  171. '【偶・2】今まで吹いていた風がぴたりと止まりました。',
  172. '【偶・3】お日様の匂いがします。(ハートフル+1)',
  173. '【偶・4】一陣の風が吹きすぎてゆきました。',
  174. '【偶・5】何か重いものが落ちた音がしました。(カタストロフ+1)',
  175. '【偶・6】視線を感じました。'
  176. ],
  177. },
  178. "TWILIGHT" => {
  179. name: "黄昏",
  180. table: [
  181. '【奇・1】人影を見たような気がします。(ルナティック+1)',
  182. '【奇・2】やけに色の薄い夕暮れで、なにもかもが灰色に見えます。',
  183. '【奇・3】鮮やかな夕焼けになりました。',
  184. '【奇・4】ふと、自分の影が気になって見つめてしまいました。(カタストロフ+1)',
  185. '【奇・5】窓硝子かなにかが、夕陽を照り返して輝いています。',
  186. '【奇・6】葉ずれの音が、やけに大きくざわめいています。',
  187. '【偶・1】一番星を見つけました。(ハートフル+1)',
  188. '【偶・2】物陰に夜の気配がわだかまっています。',
  189. '【偶・3】蝙蝠の影らしきものが音もなく舞っています。',
  190. '【偶・4】木の枝にびっしりと、鳥たちが身を寄せ合っています。',
  191. '【偶・5】むやみに月が大きく見えます。',
  192. '【偶・6】ものの境い目があいまいになり、全てが溶けて混ざり合ってしまいそうです。(ロマンティック+1)'
  193. ],
  194. },
  195. "NIGHT" => {
  196. name: "夜中",
  197. table: [
  198. '【奇・1】なかなか眠くなれません。',
  199. '【奇・2】ひどく眠くて、今にも寝てしまいそうです。(ハートフル+1)',
  200. '【奇・3】赤い月が空に低くかかっています。',
  201. '【奇・4】月の青い光が降り注いでいます。(ロマンティック+1)',
  202. '【奇・5】特に星の綺麗な夜です。',
  203. '【奇・6】灯していた明かりがざわめくように揺らいでいます。(ルナティック+1)',
  204. '【偶・1】月を隠しながら、薄い雲が通り過ぎていきます。',
  205. '【偶・2】星一つ見えない闇夜です。',
  206. '【偶・3】どこからか談笑の声が聞こえた気がします。',
  207. '【偶・4】流れ星が流れました。',
  208. '【偶・5】コトリと硬い音がしました。(カタストロフ+1)',
  209. '【偶・6】どこからかとても美味しそうな匂いがただよってきます。'
  210. ],
  211. },
  212. "MIDNIGHT" => {
  213. name: "夜更け",
  214. table: [
  215. '【奇・1】時計の音がやけに大きく響いています。(カタストロフ+1)',
  216. '【奇・2】夢から醒めましたが、どんな夢か覚えていません。',
  217. '【奇・3】足音を聞いた気がします。',
  218. '【奇・4】ぼそぼそと話す声を聞いた気がします。(ロマンティック+1)',
  219. '【奇・5】ひどく喉が渇いています。',
  220. '【奇・6】ひどくお腹がすいています。(ハートフル+1)',
  221. '【偶・1】寝苦しさを感じています。',
  222. '【偶・2】眠気が全く訪れません。',
  223. '【偶・3】急に月の光を浴びました。(ルナティック+1)',
  224. '【偶・4】見慣れたものの影が全く別のものに見えました。',
  225. '【偶・5】闇がやけに深く感じられます。',
  226. '【偶・6】違和感のある香りを感じました。'
  227. ],
  228. },
  229. "NORBLE" => {
  230. name: "貴族趣味",
  231. table: [
  232. '【奇・1】毛足の長い絨毯に足音を吸い取られてしまいました。',
  233. '【奇・2】見とれるほど豪奢な調度があります。',
  234. '【奇・3】気後れするほど豪奢な調度があります。',
  235. '【奇・4】誰かがどこかから窺っているような気がしました。(ルナティック+1)',
  236. '【奇・5】曇り一つ無いところに思わず手をついてしまいました。',
  237. '【奇・6】窮屈なくらい、気品にあふれています。',
  238. '【偶・1】仰々しすぎて、ちょっと嫌味に思えなくもありません。',
  239. '【偶・2】豪華でよそ行きな雰囲気の中に、生活の気配がちょっとだけ、混ざりこんでいます。(ハートフル+1)',
  240. '【偶・3】【素敵なオブジェ(支押)】(グッズ)が飾られています。',
  241. '【偶・4】わけもなく空しさが募りました。(ロマンティック+1)',
  242. '【偶・5】飾り縁のような窓に切り取られた外の景色が、ひどく遠く見えます。(カタストロフ+1)',
  243. '【偶・6】いつか聞いたお話の、お姫様を思い出しました。'
  244. ],
  245. },
  246. "MARCHEN" => {
  247. name: "メルヒェン",
  248. table: [
  249. '【奇・1】懐かしさを覚える木の香りがします。(カタストロフ+1)',
  250. '【奇・2】周りにあるのはなんの変哲もないものばかりです。',
  251. '【奇・3】部屋のどこかがきしみました。',
  252. '【奇・4】小さな音がします。',
  253. '【奇・5】生活のぬくもりが、確かに刻まれています。(ハートフル+1)',
  254. '【奇・6】どこかで読んだお話の記憶と、目の前の風景が重なりました。',
  255. '【偶・1】もったりとした野暮ったさにあふれています。',
  256. '【偶・2】よく乾いたハーブと干草の香りがわずかに漂っています。(ロマンティック+1)',
  257. '【偶・3】飾り気がなくとも使いやすそうな調度が、存在感を放っています。',
  258. '【偶・4】おいしそうな匂いが一度だけ、鼻をくすぐりました。',
  259. '【偶・5】歩くと、床がことことと足音をたてます。',
  260. '【偶・6】なにかがひとつ、足りない気がします。(ルナティック+1)'
  261. ],
  262. },
  263. "COLONIAL" => {
  264. name: "コロニアル",
  265. table: [
  266. '【奇・1】重厚な調度が征服欲を刺激します。',
  267. '【奇・2】床に傷を見つけてしまいました。',
  268. '【奇・3】重厚な調度に頼もしさを感じます。',
  269. '【奇・4】堅固すぎて、逆にいわく言いがたい不吉さを感じます。(カタストロフ+1)',
  270. '【奇・5】壁になにかが架けられていた跡が残っています。',
  271. '【奇・6】ぐるっと回る椅子がなんだかすごく魅力的です。(ハートフル+1)',
  272. '【偶・1】しっかりした錠がだらしなく開いていました。',
  273. '【偶・2】威厳を演出しすぎていて、かえって下品かもしれません。',
  274. '【偶・3】外からの光が不思議な静けさをもたらしました。(ロマンティック+1)',
  275. '【偶・4】靴音が立ちました。(ルナティック+1)',
  276. '【偶・5】革の匂いがかすかに漂っています。',
  277. '【偶・6】そこの頑丈そうな机は、なんだか座り心地がよさそうです。'
  278. ],
  279. },
  280. "SHELF" => {
  281. name: "本棚のある場所",
  282. table: [
  283. '【奇・1】明らかに踏み台に使ったらしく、【大判の本(打押)】(グッズ)が積み上げてあります。(ハートフル+1)',
  284. '【奇・2】古びた紙の匂いが辺りを満たしています。',
  285. '【奇・3】【薄い本(打察)】(グッズ)が一冊、ぱたりと音を立てて倒れました。',
  286. '【奇・4】なぜか本棚の一段がまるごと、からっぽになっています。',
  287. '【奇・5】【気になる本(純押)】(グッズ)があるのですが、本棚の天辺に乗っている上非常に重そうです。(ルナティック+1)',
  288. '【奇・6】【破り取られた絵本の頁(支従)】(グッズ)が一葉、無残な破れ目をさらしています。',
  289. '【偶・1】【広げっぱなしの本(支押)】(グッズ)にひどい落書きがされています。',
  290. '【偶・2】全集の一冊が欠けていました。(ロマンティック+1)',
  291. '【偶・3】棚にきちんと本が納められておらず、バラバラで乱雑に押し込まれています。',
  292. '【偶・4】本の隙間からなにかの気配を感じた気がします。',
  293. '【偶・5】インクが乾いて干からびた、【インク瓶(従察)】(グッズ)と【万年筆(打押)】(グッズ)がテーブルに乗っています。(カタストロフ+1)',
  294. '【偶・6】【押し花(純察)】(グッズ)が一輪、落ちていました。'
  295. ],
  296. },
  297. "LITTLE" => {
  298. name: "小さな妹の部屋",
  299. table: [
  300. '【奇・1】つまづいてしまった【玩具(従純)】(グッズ)が、ころりと可愛らしい音を立てました。',
  301. '【奇・2】シーツ(テーブルクロス)がくちゃくちゃです。',
  302. '【奇・3】とんでもないところに食べこぼしの跡を見つけました。',
  303. '【奇・4】過ぎたおいたの跡が、部屋に華々しく残っています。',
  304. '【奇・5】こっそり隠したつもりのおやつが山を成しています。',
  305. '【奇・6】脱ぎ散らかされた服が所在なさげにふて寝しています。',
  306. '【偶・1】やさしい子守歌を思い出しました。(ハートフル+1)',
  307. '【偶・2】見る物全てがいちいち勘に障ります。(ルナティック+1)',
  308. '【偶・3】かわいらしい【食器(純押)】(グッズ)が置いてありました。(ロマンティック+1)',
  309. '【偶・4】わけもなく、涙がこぼれてきます。',
  310. '【偶・5】壊してしまった【がらくた(純従)】(グッズ)が、こっそり隠してありました。',
  311. '【偶・6】ふと、この棲み処の主は、どんな素敵な人になるだろう、と思いました。(カタストロフ+1)'
  312. ],
  313. },
  314. "ELDER" => {
  315. name: "素敵なお姉さまの部屋",
  316. table: [
  317. '【奇・1】床に映った影が、ゆっくりと動いていきます。(カタストロフ+1)',
  318. '【奇・2】きゅっ、と音が立ちました。',
  319. '【奇・3】自然に背筋が伸びてしまいます。',
  320. '【奇・4】ふとほのかに甘い、柔らかな香りが漂いました。(ロマンティック+1)',
  321. '【奇・5】ほのかに確かににじみ出る魅力に、ちょっと嫉妬してしまいます。',
  322. '【奇・6】素敵な【ベルト(支従)】がありました。(ルナティック+1)',
  323. '【偶・1】お茶が冷めていました。',
  324. '【偶・2】ちょっとくたびれた【可愛らしい小物(純察)】(グッズ)が、物陰にこっそり置いてありました。',
  325. '【偶・3】衣擦れの音がしました。',
  326. '【偶・4】ダイビングにもってこいのベッドがあります。(ハートフル+1)',
  327. '【偶・5】気後れしそうなほど完成度の高い、【手作り品(支押)】(グッズ)が無造作に置いてあります。',
  328. '【偶・6】【部屋着(従純)】(コーディネート)がハンガーにかけられています。'
  329. ],
  330. },
  331. "ATERIEL" => {
  332. name: "アトリエ",
  333. table: [
  334. '【奇・1】棚に【道具(打支)】(グッズ)がきちんと整頓されています。',
  335. '【奇・2】【メモや図面(支押)】(グッズ)が書き散らされています。',
  336. '【奇・3】【壊れた道具(従察)】が積み上げられています。',
  337. '【奇・4】【作りかけらしい作品(純押)】(グッズ)が無造作に放置されています。',
  338. '【奇・5】めちゃくちゃに壊された作品の残骸が散乱しています。(ルナティック+1)',
  339. '【奇・6】【見慣れない道具(打純)】(グッズ)が大切そうに置いてあります。',
  340. '【偶・1】食べかけの食事がそのままになっています。',
  341. '【偶・2】【ジャケット(打純)】(グッズ)が脱ぎ捨てられています。(ロマンティック+1)',
  342. '【偶・3】積み上げられていたものが、派手な音を立てて崩れました。',
  343. '【偶・4】何気なく触れたところに、インク(や絵の具等)がべっとりついていました。',
  344. '【偶・5】引き出しが一つ、丸々抜き去られています。(カタストロフ+1)',
  345. '【偶・6】「作業中、入るな!」と書かれた【紐付きのプレート(支押)】(グッズ)が手に取りやすい位置に置いてあります。(ハートフル+1)'
  346. ],
  347. },
  348. "OPEN" => {
  349. name: "集まれる場所",
  350. table: [
  351. '【奇・1】かつての楽しい出来事の余韻が、伝わってくるような気がします。(ハートフル+1)',
  352. '【奇・2】テーブルクロスのしみが、涙の跡のように思えました。(ロマンティック+1)',
  353. '【奇・3】鉄錆くさい臭いがかすかに鼻を突きます。',
  354. '【奇・4】ぜんぜん片付けられておらず、散らかり放題です。',
  355. '【奇・5】なぜか1枚だけ、【割れた皿(支押)】(グッズ)がそっくりそのまま床に放置されています。',
  356. '【奇・6】誰かが貼った「RESERVED(予約済み)」の【張り紙(支打)】(グッズ)が、堂々と居座っています。',
  357. '【偶・1】整理されすぎていて、人のぬくもりが感じられません。',
  358. '【偶・2】部屋の片隅に、布にくるまれた何か大きなモノが置いてあります。',
  359. '【偶・3】完璧な作法で【食器(従察)】(グッズ)が並べられていますが、誰も、また何も、出てくる気配はありません。',
  360. '【偶・4】壁の向こうを、大勢が賑やかに通り過ぎてゆく気配がします。(カタストロフ+1)',
  361. '【偶・5】直前に行われたパーティで余ったらしいお菓子が、「ご自由に」の書置きとともに残されています。',
  362. '【偶・6】壁に【ナイフ(支従)】(グッズ)が突き立っています。(ルナティック+1)'
  363. ],
  364. },
  365. "HAUNTED" => {
  366. name: "精神的瑕疵物件",
  367. table: [
  368. '【奇・1】赤黒い染みを見つけてしまいました。',
  369. '【奇・2】叩くような、はじけるような音が断続的に聞こえるような気がします。',
  370. '【奇・3】悪寒がします。',
  371. '【奇・4】ふと手を触れた場所が、不自然に冷たく湿って感じました。',
  372. '【奇・5】何人か余分に、人の気配を感じるような気がしてしかたありません。',
  373. '【奇・6】ふっ、と辺りがいくらか暗くなって、また元に戻りました。',
  374. '【偶・1】細く開いていた隙間が閉じる瞬間を見てしまいました。(カタストロフ+1)',
  375. '【偶・2】何かが足をするりと撫でました。(ルナティック+1)',
  376. '【偶・3】耳元でつぶやきが聞こえました。多分。(ロマンティック+1)',
  377. '【偶・4】出た……と思ったらものの影でした。(ハートフル+1)',
  378. '【偶・5】空気がゆっくりと渦をまいて、肌を撫でています。',
  379. '【偶・6】うっすらと手形がついています。'
  380. ],
  381. },
  382. "SIMPLE" => {
  383. name: "侘び住まい",
  384. table: [
  385. '【奇・1】若干、風通しがよすぎるようです。',
  386. '【奇・2】いろいろすっきりしています。',
  387. '【奇・3】壁のひびを見つけました。',
  388. '【奇・4】隅っこに穴が開いています。',
  389. '【奇・5】思わず深呼吸してしまいました。',
  390. '【奇・6】壁と柱の隙間から、外の光が細く漏れてきます。',
  391. '【偶・1】ふと気づくと、掃除したらよさそうな場所を探している自分がいます。(ハートフル+1)',
  392. '【偶・2】ぱらっと何かこぼれた音がしました。',
  393. '【偶・3】軋んだ音がした瞬間、棲み処全体が傾いでいくような錯覚に襲われました。(ルナティック+1)',
  394. '【偶・4】使い込まれた艶が用の美を控えめに放っています。(ロマンティック+1)',
  395. '【偶・5】二度と落ちなさそうな汚れがこびりついています。',
  396. '【偶・6】このまま誰かの思い出の中に閉じこめられてしまいそうな気分になりました。(カタストロフ+1)'
  397. ],
  398. },
  399. "LARGE" => {
  400. name: "広い場所",
  401. table: [
  402. '【奇・1】がらんとした広さに、胸を衝かれました。',
  403. '【奇・2】誰かの残り香が、ほのかに甘く漂っています。(ロマンティック+1)',
  404. '【奇・3】扉がふいに開きましたが、誰も入ってきません。(カタストロフ+1)',
  405. '【奇・4】自分の足音がやけに大きく響き渡りました。',
  406. '【奇・5】ふともらした独り言が、広い部屋の中にぽつりと消えていきました。(ルナティック+1)',
  407. '【奇・6】壁に素敵な絵が飾られています。',
  408. '【偶・1】部屋の片隅に、壊れたオブジェが打ち捨てられています。',
  409. '【偶・2】掃除道具が出しっぱなしです。(ハートフル+1)',
  410. '【偶・3】床に派手な傷がついています。',
  411. '【偶・4】鉢植えが枯れています。',
  412. '【偶・5】不意に空気が揺れ動くのを感じました。',
  413. '【偶・6】天井がきしんだような気がします。'
  414. ],
  415. },
  416. "CORRIDOR" => {
  417. name: "廊下",
  418. table: [
  419. '【奇・1】窓が開け放たれています。(カタストロフ+1)',
  420. '【奇・2】パタン、と扉の閉まる音がしました。',
  421. '【奇・3】人影が、向こうの曲がり角に姿を消したような気がします。(ロマンティック+1)',
  422. '【奇・4】壁のランプが落ちて割れています。',
  423. '【奇・5】天井の染みにふと目を奪われました。',
  424. '【奇・6】壁に掛けられた絵がわずかに傾いています。',
  425. '【偶・1】愛を誓うささやかな落書きがありました。(ハートフル+1)',
  426. '【偶・2】壁紙が破れ、小さな影を作っています。',
  427. '【偶・3】絨毯が擦り切れています。',
  428. '【偶・4】自分の立てた音がやけに大きく耳に残りました。(ルナティック+1)',
  429. '【偶・5】【誰かの落し物(打察)】(グッズ)が落ちています。',
  430. '【偶・6】空っぽの飾り棚が置かれています。'
  431. ],
  432. },
  433. "STAIRS" => {
  434. name: "階段",
  435. table: [
  436. '【奇・1】踊り場に大きな姿見が掛けられています。(カタストロフ+1)',
  437. '【奇・2】手すりが使い込まれたつややかな輝きを放っています。(ハートフル+1)',
  438. '【奇・3】手すりの一部が壊れています。',
  439. '【奇・4】重いものをぶつけた痕が残っています。',
  440. '【奇・5】【片っぽだけの靴(従純)】(グッズ)残されていました。(ロマンティック+1)',
  441. '【奇・6】段が嫌な音を立てて大きくきしみました。',
  442. '【偶・1】隅に埃がたまっています。',
  443. '【偶・2】なぜか、壊れた家具が階段の途中に積み上げてあります。',
  444. '【偶・3】上の階から誰かの足音が聞こえてきます。',
  445. '【偶・4】下の階からぼそぼそと声が聞こえたような気がします。(ルナティック+1)',
  446. '【偶・5】差し込む日差しが段に複雑な陰影を作っています。',
  447. '【偶・6】一段踏み外しました。'
  448. ],
  449. },
  450. "COSY" => {
  451. name: "居心地のいい場所",
  452. table: [
  453. '【奇・1】一瞬、物音が全て途絶えました。',
  454. '【奇・2】壁の模様が動いたような気がします。',
  455. '【奇・3】蔦が少しばかり這いこんでいました。(カタストロフ+1)',
  456. '【奇・4】妙な息苦しさを覚えました。',
  457. '【奇・5】部屋のどこかがきしみました。',
  458. '【奇・6】小さな明かりがあかあかと揺れています。(ハートフル+1)',
  459. '【偶・1】梁の向こうになにかの気配を感じました。',
  460. '【偶・2】窓が急に音を立てました。',
  461. '【偶・3】敷物のすみがわずかに盛り上がっています。(ルナティック+1)',
  462. '【偶・4】何の前触れもなく、椅子が倒れました。',
  463. '【偶・5】わけもなく寂しさが募ります。(ロマンティック+1)',
  464. '【偶・6】軽い眠気に教われました。'
  465. ],
  466. },
  467. "TERRACE" => {
  468. name: "テラス・ベランダ",
  469. table: [
  470. '【奇・1】木の枝や木の葉が積もっています。',
  471. '【奇・2】【小鳥(純察)】(コンパニオン)がてすりでさえずっています。',
  472. '【奇・3】誰かの洗濯物が風に翻っています。(ハートフル+1)',
  473. '【奇・4】てすりが壊れています。',
  474. '【奇・5】バタン、と扉(窓)の閉ざされる音がしました。',
  475. '【奇・6】テラスから覗く部屋の中が、暗く影に沈んでいます。(カタストロフ+1)',
  476. '【偶・1】下の方から、楽しげなさざめきが聞こえた気がします。',
  477. '【偶・2】強い風が通り過ぎました。',
  478. '【偶・3】なにかの影が上を通り過ぎました。(ルナティック+1)',
  479. '【偶・4】雨ざらしのテーブルと椅子が一揃いあります。',
  480. '【偶・5】雨樋から雫がしたたっています。(ロマンティック+1)',
  481. '【偶・6】軒(窓、破風)の飾りが壊れ、【かけら(従察)】(グッズ)が落ちています。'
  482. ],
  483. },
  484. "GARRET" => {
  485. name: "屋根裏",
  486. table: [
  487. '【奇・1】隙間風が【空っぽの小箱(打支)】(グッズ)を揺らして床に落としました。',
  488. '【奇・2】小さな窓から差し込む日差しの中に、埃が舞っています。(ロマンティック+1)',
  489. '【奇・3】【古ぼけてほつれた衣装(従純)】(コーディネート)が見つかりました。(ハートフル+1)',
  490. '【奇・4】クローゼットの扉が、ほんのわずか開いています。',
  491. '【奇・5】【片手(片足)がもげたぬいぐるみ(純支)】(グッズ)が見つかりました。',
  492. '【奇・6】【ガラスの破片(支純)】(グッズ)で小さな傷を作ってしまいました。',
  493. '【偶・1】鍵穴のない、頑丈で重たい大きな箱があります。',
  494. '【偶・2】埃だらけのクッションが積まれています。',
  495. '【偶・3】がらくたにかぶせられた埃避けの布がかすかに揺れています。(カタストロフ+1)',
  496. '【偶・4】蜘蛛の巣がかかっています。',
  497. '【偶・5】【蛾の死骸(従察)】(グッズ)を見つけました。',
  498. '【偶・6】ねずみかなにかが壁の中を駆け抜けていく小さな物音がしました。(ルナティック+1)'
  499. ],
  500. },
  501. "KITCHEN" => {
  502. name: "台所",
  503. table: [
  504. '【奇・1】【よく洗われた食器(従純)】(グッズ)が輝きを放っています。(ハートフル+1)',
  505. '【奇・2】【銀器(支打)】(グッズ)がくすんでしまっています。',
  506. '【奇・3】水の樽がほとんど空になっていました。',
  507. '【奇・4】【汚れた食器(従支)】(グッズ)が流しを占領しています。',
  508. '【奇・5】【生ごみ(従支)】(グッズ)が異臭を放っています。(ルナティック+1)',
  509. '【奇・6】血痕が点々と散らばっています。',
  510. '【偶・1】【ジャムや砂糖漬けの瓶(純打)】が宝石の列のように並んでいます。',
  511. '【偶・2】鍋がコトコトと幸せそうな音を立てていますが、人が見当たりません。(カタストロフ+1)',
  512. '【偶・3】ついさっきまで人が立ち働いていたらしく、ぬくもりがまだ残っています。(ロマンティック+1)',
  513. '【偶・4】蟻の列が一生懸命おつかいに励んでいます。',
  514. '【偶・5】隅の方に【大きなナメクジ(純従)】(コンパニオン)がへばりついています。',
  515. '【偶・6】分捕り品に齧り付いている【ねずみ(支従)】(コンパニオン)と目が合ってしまいました。'
  516. ],
  517. },
  518. "BATH" => {
  519. name: "浴室",
  520. table: [
  521. '【奇・1】盛大に滑って転んでしまいました。(ハートフル+1)',
  522. '【奇・2】下水の饐えた匂いがします。',
  523. '【奇・3】天井から雫がやけにしたたっています。',
  524. '【奇・4】【お風呂用のおもちゃ(純従)】(グッズ)がさみしげに転がっています。(カタストロフ+1)',
  525. '【奇・5】空のバスタブの排水溝に、湿った長い髪の毛が絡んでいます。',
  526. '【奇・6】バスタブに泡だらけのお湯が残っています。',
  527. '【偶・1】シャワーが外れたまま床を這っています。(ロマンティック+1)',
  528. '【偶・2】床のタイルにひどいひびが入っています。',
  529. '【偶・3】ここしばらく、誰も使った形跡がなく空気が乾いてすらいます。',
  530. '【偶・4】【誰かの服(従打)】(コーディネート)がバスタブに投げ込まれ、ぐちゃぐちゃになっています。',
  531. '【偶・5】不健康にじめついていて、どこもかしこもカビだらけです。',
  532. '【偶・6】なにかが這い回ったような跡がありました。(ルナティック+1)'
  533. ],
  534. },
  535. "REST" => {
  536. name: "化粧室",
  537. table: [
  538. '【奇・1】鏡の中の自分が別の顔をしていたような気がします。(カタストロフ+1)',
  539. '【奇・2】鬱陶しく虫が飛び回っています。',
  540. '【奇・3】蛇口から水がしたたっています。',
  541. '【奇・4】不快な匂いが強いようです。',
  542. '【奇・5】【清潔なタオル(純従)】(グッズ)が整えられています。(ハートフル+1)',
  543. '【奇・6】壊れているらしい便器にガラクタがつっこんであります。',
  544. '【偶・1】閉ざされた個室の中で、ぼそぼそと声がしたような気がします。(ロマンティック+1)',
  545. '【偶・2】誰かの【ささやかなアクセサリ(支打)】(グッズ)が置き忘れられています。',
  546. '【偶・3】【清掃用具(打従)】(グッズ)が放り出されています。',
  547. '【偶・4】扉の向こうで人の気配が立ち去りました。(ルナティック+1)',
  548. '【偶・5】清掃用具のクローゼットの扉の下から、水が漏れ広がっています。',
  549. '【偶・6】換気窓の近くで空気がゆるく蠢いています。'
  550. ],
  551. },
  552. "CELLER" => {
  553. name: "地下倉庫",
  554. table: [
  555. '【奇・1】なにかべとべとしたものに触ってしまいました。',
  556. '【奇・2】ひんやりとした空気がまとわりついてきます。',
  557. '【奇・3】かすかに悪臭が漂ってきます。',
  558. '【奇・4】作業台のようなものの上を、赤黒い染みが覆っています。(ルナティック+1)',
  559. '【奇・5】【ムカデ(純支)】(コンパニオン)がじっとしています。',
  560. '【奇・6】【重たそうな麻袋(従支)】(コンテナ)が積み上げられています。',
  561. '【偶・1】灯されたランプがチリチリと小さな音を立てました。(カタストロフ+1)',
  562. '【偶・2】積まれた石炭に、【スコップ(支押)】(グッズ)が突っ込まれています。',
  563. '【偶・3】食べ物を収めた棚があります。(ハートフル+1)',
  564. '【偶・4】無愛想でそっけない造りの椅子が転がっています。',
  565. '【偶・5】床の一部が磨り減り、妙に滑らかになっています。',
  566. '【偶・6】梁の上から、視線を感じました。(ルナティック+1)'
  567. ],
  568. },
  569. "LUMBER" => {
  570. name: "物置",
  571. table: [
  572. '【奇・1】壁の隙間の向こうを何かの影が通り過ぎました。',
  573. '【奇・2】【気になる箱(従支)】(コンテナ)があるのですが、がらくたの山に埋もれて手が出せません。(ロマンティック+1)',
  574. '【奇・3】積まれていたがらくたの一つが、目を逸らした隙に消えたような気がします。(ルナティック+1)',
  575. '【奇・4】壊れた家具の下で、【人形(純支)】(グッズ)が潰されています。',
  576. '【奇・5】【虫の死骸(純打)】(グッズ)を見つけました。',
  577. '【奇・6】【安っぽいヒカリモノ(純打)】(グッズ)がたくさん詰まったバスケットがあります。(ハートフル+1)',
  578. '【偶・1】【庭いじりの道具(従支)】(グッズ)が無造作に立てかけてあります。',
  579. '【偶・2】黴くさい臭いで息が詰まりそうです。',
  580. '【偶・3】どこかでがらくたが崩れ、大きな音を立てました。',
  581. '【偶・4】床の一部が抜けています。',
  582. '【偶・5】片隅の暗がりから視線を感じました。',
  583. '【偶・6】なんの前触れもなく、物置全体が小さくきしみました。(カタストロフ+1)'
  584. ],
  585. },
  586. "GARDEN" => {
  587. name: "庭園",
  588. table: [
  589. '【奇・1】【季節の花(純支)】(グッズ)が美しく咲き乱れています。(ハートフル+1)',
  590. '【奇・2】せっかくの花壇が、無残に踏みにじられなぎ倒されています。',
  591. '【奇・3】【庭いじりの道具(従押)】(グッズ)が放り出してあります。',
  592. '【奇・4】物陰から小動物のような影が逃げ去っていきました。',
  593. '【奇・5】手入れが悪く、栽培物が雑草に押され気味です。',
  594. '【奇・6】枯れてしまった苗が、そのまま放置されています。(カタストロフ+1)',
  595. '【偶・1】【虫(純従)】(コンパニオン)が悠々と這っています。',
  596. '【偶・2】ふいの強い風に、草木がざわりと不安な音を立てました。',
  597. '【偶・3】どこからともなく、鮮烈な花の香りが漂ってきます。(ロマンティック+1)',
  598. '【偶・4】藤棚の作る蔭が、素敵に居心地よく見えます。',
  599. '【偶・5】植え込みがよく育っているのですが、茂りすぎてなんだか怖いようです。(ルナティック+1)',
  600. '【偶・6】【花の名前を書いた札(打純)】(グッズ)が打ち棄てられています。'
  601. ],
  602. },
  603. "WASTED" => {
  604. name: "廃園",
  605. table: [
  606. '【奇・1】伸び放題の草が風にざわざわとざわめいています。',
  607. '【奇・2】背丈よりも高い、見上げるような草むらが生い茂っています。',
  608. '【奇・3】【清楚な野の花(純従)】(グッズ)が端然と咲いています。(ハートフル+1)',
  609. '【奇・4】草むらの中をなにかがざわざわと通り過ぎていきます。',
  610. '【奇・5】花壇の残骸に躓きました。',
  611. '【奇・6】アーチの残骸に絡む枯れた蔓草の上から、元気な蔓草が巻きついています。(ロマンティック+1)',
  612. '【偶・1】枯れた噴水があります。',
  613. '【偶・2】でこぼこに割れた敷石の隙間から、雑草が茂っています。',
  614. '【偶・3】全く草の生えていない一角があります。(カタストロフ+1)',
  615. '【偶・4】綺麗な彫刻の、半分くらいに割れた【かけら(従察)】(グッズ)があります。',
  616. '【偶・5】大きな虫瘤があります。',
  617. '【偶・6】虫が素早く、石の下に這いこんでいきました。(ルナティック+1)'
  618. ],
  619. },
  620. "RUIN" => {
  621. name: "廃屋",
  622. table: [
  623. '【奇・1】天井や床が派手に崩壊していて、踏み込めない一角があります。',
  624. '【奇・2】何か金属の部品が真っ二つになっていました。',
  625. '【奇・3】硝子の破片が散乱しています。',
  626. '【奇・4】ひどい隙間風が這いこんできています。',
  627. '【奇・5】絡み付いた茨に可憐な花が付いていました。(ロマンティック+1)',
  628. '【奇・6】壊れてひっくり返った家具が黙然としています。',
  629. '【偶・1】【汚れた人形(従察)】(グッズ)が転がっています。',
  630. '【偶・2】あたり一面を、茨(蔦)がびっしり覆っています。',
  631. '【偶・3】紐状のものが垂れ下がっています。(ルナティック+1)',
  632. '【偶・4】文字が乱れていて【読めないノート(打押)】(グッズ)が置き去られていました。(カタストロフ+1)',
  633. '【偶・5】壁が崩れていますが、まだ穴にはなっていません。',
  634. '【偶・6】虫がせっせとなにかを運んでいます。(ハートフル+1)'
  635. ],
  636. },
  637. "SHORE" => {
  638. name: "水のほとり",
  639. table: [
  640. '【奇・1】水面に波紋が広がっていきます。',
  641. '【奇・2】視界の外で水音がしました。',
  642. '【奇・3】生臭い匂いがします。',
  643. '【奇・4】湿った空気が肌を撫でます。(ロマンティック+1)',
  644. '【奇・5】うっかり足元を濡らせてしまいました。',
  645. '【奇・6】遠くを水鳥が滑っていきました。(ハートフル+1)',
  646. '【偶・1】水面に映した自分の顔が、不自然にくっきりとしていました。(カタストロフ+1)',
  647. '【偶・2】水がやけに濁っています。',
  648. '【偶・3】底の方に何か沈んでいるのを見てしまったような気がします。',
  649. '【偶・4】【ガラクタ(打従)】(グッズ)が所在なさげに浮かんでいます。',
  650. '【偶・5】一瞬寒気に襲われました。(ルナティック+1)',
  651. '【偶・6】水の中で、魚の影が翻りました。'
  652. ],
  653. },
  654. }.freeze
  655. end
  656. end
  657. end

lib/bcdice/game_system/ShuumatsuBargainWars.rb

100.0% lines covered

100.0% branches covered

37 relevant lines. 37 lines covered and 0 lines missed.
6 total branches, 6 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class ShuumatsuBargainWars < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "ShuumatsuBargainWars"
  7. # ゲームシステム名
  8. 1 NAME = "終末買い物戦争"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "しゆうまつはあけんうおおす"
  11. 1 HELP_MESSAGE = <<~TEXT
  12. ・行為判定 (nBGk+y>=t)n:ダイス数、k:心根、y:修正値(省略可)、t:目標値
  13. 例)3BG1>=3 2BG3+1>=4 4BG5-1>=3
  14. ・アイテム表
  15. ・RT 回復系アイテム表
  16. ・CT 便利系アイテム表
  17. ・WT 武器系アイテム表
  18. ・WG ワゴン(全アイテムランダム)
  19. ・ET イベント表
  20. ・TT トラブル表
  21. TEXT
  22. 1 def initialize(command)
  23. 11 super(command)
  24. 11 @sort_barabara_dice = true
  25. 11 @d66_sort_type = D66SortType::ASC
  26. end
  27. 1 RecoveryItemTable = DiceTable::D66Table.new(
  28. '回復系アイテム表',
  29. D66SortType::ASC,
  30. {
  31. 11 => '飴玉',
  32. 12 => 'エナジードリンク',
  33. 13 => 'せんべい',
  34. 14 => '餅',
  35. 15 => 'ロウソク',
  36. 16 => '酒',
  37. 22 => '寿司',
  38. 23 => 'ばんそうこう',
  39. 24 => 'お布団',
  40. 25 => 'カレー',
  41. 26 => '消毒液',
  42. 33 => '缶詰',
  43. 34 => 'みたらし団子',
  44. 35 => '骨付き肉',
  45. 36 => 'ステーキ',
  46. 44 => 'うちわ',
  47. 45 => 'ぬいぐるみ',
  48. 46 => 'のり',
  49. 55 => '美容液',
  50. 56 => '黄色いハンカチ',
  51. 66 => '洗剤',
  52. }
  53. )
  54. 1 ConvenienceItemTable = DiceTable::D66Table.new(
  55. '便利系アイテム表',
  56. D66SortType::ASC,
  57. {
  58. 11 => 'ちくわ',
  59. 12 => '焼き芋',
  60. 13 => 'トイレットペーパー',
  61. 14 => '熊手',
  62. 15 => '胡椒',
  63. 16 => '鏡',
  64. 22 => '割りばし',
  65. 23 => '輪ゴム',
  66. 24 => '塩の結晶',
  67. 25 => 'プチプチマット',
  68. 26 => '長靴',
  69. 33 => 'バケツ',
  70. 34 => 'アルミホイル',
  71. 35 => '下敷き',
  72. 36 => '長芋',
  73. 44 => '鉛筆',
  74. 45 => 'まな板',
  75. 46 => 'フライパン',
  76. 55 => 'ほうき',
  77. 56 => 'クラッカー',
  78. 66 => '消臭スプレー',
  79. }
  80. )
  81. 1 WeaponItemTable = DiceTable::D66Table.new(
  82. '武器系アイテム表',
  83. D66SortType::ASC,
  84. {
  85. 11 => 'アズキアイス',
  86. 12 => 'スプーン',
  87. 13 => 'フォーク',
  88. 14 => 'カミソリ',
  89. 15 => '電池',
  90. 16 => 'デッキブラシ',
  91. 22 => '傘',
  92. 23 => '物干し竿',
  93. 24 => '鉄パイプ',
  94. 25 => 'くぎ打ち機',
  95. 26 => 'モンキーレンチ',
  96. 33 => 'ハエタタキ',
  97. 34 => '鎌',
  98. 35 => '蛍光灯',
  99. 36 => '包丁',
  100. 44 => 'ハサミ',
  101. 45 => 'ショベル',
  102. 46 => '釣り竿',
  103. 55 => '芝刈り機',
  104. 56 => 'ステッキ',
  105. 66 => '小麦粉',
  106. }
  107. )
  108. TABLES = {
  109. 1 "ET" => DiceTable::Table.new(
  110. "イベント表",
  111. "2D6",
  112. [
  113. "ドッキン!一目惚れ!好きなキャラクターを1人選ぶ。このセッション中その相手との関係の深度を互いに3以上にすることができた場合、シナリオの結末に関係なく貴方は完全無欠のハッピーエンドを迎え経験点を100点得る。達成できなかった場合、エンディングフェイズで目が覚める。",
  114. "おや?こんな所にアイテムが転がっている。ランダムに選んだアイテムを獲得する。そのアイテムの種別が支援・計画ならば[技術]/5の判定に成功すれば手番を消費せずそのアイテムを使用しても良い。",
  115. "チームメンバーと二人っきりになる。ちょっといい雰囲気かも。好きなキャラクターを目標に選び、『関係』のチェックを外す事ができる。",
  116. "あぶな~い!チームメンバーに危機が襲い掛かる。PCの中からランダムに1人を選び[武力]/5の判定を行う。成功すると互いに『関係』を結ぶことができる。失敗すると2人とも体力に1d6点のダメージ。",
  117. "ちょっとお食事でも如何?自身の体力3点と活力1点を回復させる。",
  118. "穏やかな時が流れる。このメンバーならこれからも上手くやっていけそうだ。ランダムにPCを選び『関係』を獲得する。",
  119. "チームメンバーの意外な一面を覗く、まさかアイツあんな趣味があったなんて!PCの中からランダムで1人を選び[精神]/6で判定を行う。成功すると互いに『関係』を獲得する。失敗すると互いに活力が1点減少する。",
  120. "仲間と意見が対立する。アイツにだけは負けられない!関係を持つPCの中からランダムで1人を選び、対象との関係の深度を1下げてもよい(0未満にならない)。下げた場合、以降のセッション中任意の能力値が1上昇したものとして判定を行う事ができる。この効果で実際に能力値は上がらない。",
  121. "何かお手伝いをしよう。好きなキャラクターを1人選ぶ。この休憩中次に相手が判定を行う場合、その判定に修正値+1を加える。その後、目標は自分に対し『関係』を獲得する。",
  122. "酒を発見、宴だぁああ!!!PCは全員回復アイテムの「酒」の効果を使用できる。その後、自分の持つ全ての『関係』をランダムな相手に同じ《深度》で取り直す。",
  123. "不味い!敵襲だ!バナナワニにキリミウオが戦闘を仕掛けに来る。戦闘に勝利した場合、好きなアイテムを1つ得る。この処理が面倒ならば戦闘を行う代わりにPC達全員の体力の値を半分にし戦闘に勝利したものとして扱っても良い。"
  124. ]
  125. ),
  126. "TT" => DiceTable::Table.new(
  127. "トラブル表",
  128. "1D6",
  129. [
  130. "緊張感からか焦りが生じる。以降スポットフェイズに行くまでの間あらゆる判定の成功度が1減少する。",
  131. "カートの操作が効かなくなった!このラウンドは操作表を全員ダイスを振りランダムで決定する事。",
  132. "派手な振動が起き頭をぶつける。全員1d6点のダメージを受ける。",
  133. "集中力が切れて来た……全員の活力を1 点減少させる",
  134. "激しく揺さぶられ荷物が落下する。カート内にあるアイテムを1 つ選ぶ。そのアイテムを失う。",
  135. "不気味な超市場の雰囲気がパッセンジャー達の不安を煽る。特に何も起こらない。",
  136. ]
  137. ),
  138. "RT" => RecoveryItemTable,
  139. "CT" => ConvenienceItemTable,
  140. "WT" => WeaponItemTable,
  141. "WG" => DiceTable::ChainTable.new(
  142. "ワゴン",
  143. "1D6",
  144. [
  145. RecoveryItemTable,
  146. RecoveryItemTable,
  147. ConvenienceItemTable,
  148. ConvenienceItemTable,
  149. WeaponItemTable,
  150. WeaponItemTable,
  151. ]
  152. ),
  153. }.freeze
  154. 1 register_prefix('\d+BG', TABLES.keys)
  155. 1 def eval_game_system_specific_command(command)
  156. 11 return roll_bg(command) || roll_tables(command, TABLES)
  157. end
  158. 1 private
  159. 1 def roll_bg(command)
  160. 11 parser = Command::Parser.new("BG", round_type: @round_type)
  161. .has_prefix_number
  162. .has_suffix_number
  163. .restrict_cmp_op_to(:>=)
  164. 11 parsed = parser.parse(command)
  165. 11 else: 5 then: 6 return nil unless parsed
  166. 5 times = parsed.prefix_number
  167. 5 kokorone = parsed.suffix_number
  168. 5 correction = parsed.modify_number
  169. 5 target = parsed.target_number
  170. 5 dice_list = @randomizer.roll_barabara(times, 6).sort
  171. 21 success = dice_list.count { |number| number >= target - correction }
  172. 5 get_vitality = dice_list.count(kokorone)
  173. result =
  174. 5 then: 1 if dice_list.count(6) >= 2
  175. 1 else: 4 Result.critical("スペシャル! 成功度#{success + 1}、活力#{get_vitality}獲得")
  176. 4 then: 1 elsif dice_list.all?(1)
  177. 1 Result.fumble("ファンブル 活力をすべて失う")
  178. else: 3 else
  179. 3 Result.new("成功度#{success}、活力#{get_vitality}獲得")
  180. end
  181. 5 result.text = "(#{parsed}) > [#{dice_list.join(',')}] > #{result.text}"
  182. 5 return result
  183. end
  184. end
  185. end
  186. end

lib/bcdice/game_system/ShuumatsuKikou.rb

100.0% lines covered

100.0% branches covered

15 relevant lines. 15 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class ShuumatsuKikou < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'ShuumatsuKikou'
  7. # ゲームシステム名
  8. 1 NAME = '終末紀行RPG'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'しゆうまつきこう'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~HELP
  13. ■判定
  14. xB6>=5
  15. x: 能力値
  16. (汎用コマンドそのままです)
  17. ■各種表
  18. 資源の減少チェック: ResourceLose, RLose
  19. 獲得資源決定: ResourceGain, RGain
  20. □ランダムエリア決定表
  21. 都市/荒野決定: RandomArea, RArea
  22. 荒野エリア決定: RandomWaste, RWaste
  23. 都市エリア決定: RandomUrban, RUrban
  24. □ランダム障害シーン決定表
  25. シーン決定: RandomObs, RObs
  26. 技術系A: RandomObsTechA, ROTA
  27. 技術系B: RandamObsTechB, ROTB
  28. 生存系A: RandomObsSurviveA, ROSA
  29. 生存系B: RandomObsSurviveB, ROSB
  30. 戦闘系A: RandomObsCombatA, ROCA
  31. 戦闘系B: RandomObsCombatB, ROCB
  32. □ランダム旅情シーン決定表
  33. シーン決定: RandomEmo, REmo
  34. 日常系A: RandomEmoDailyA, REDA
  35. 日常系B: RandomEmoDailyB, REDB
  36. 日常系C: RandomEmoDailyC, REDC
  37. 追憶系A: RandomEmoReminiscenceA, RERA
  38. 追憶系B: RandomEmoReminiscenceB, RERB
  39. 追憶系C: RandomEmoReminiscenceC, RERC
  40. □ランダム難所シーン決定表
  41. 荒野系: RandomDangerousWaste, RDW
  42. 都市系: RandomDangerousUrban, RDU
  43. HELP
  44. 1 def eval_game_system_specific_command(command)
  45. 46 roll_tables(ALIAS[command] || command, TABLES)
  46. end
  47. # 5要素のテーブル.
  48. # 1D6 を [1..2, 3, 4, 5, 6] の5通りに割り振る.
  49. 1 class FiveItemsTable < DiceTable::RangeTable
  50. 1 def initialize(name, item1, item2, item3, item4, item5)
  51. 14 super(
  52. name,
  53. "1D6",
  54. [
  55. [1..2, item1],
  56. [3, item2],
  57. [4, item3],
  58. [5, item4],
  59. [6, item5],
  60. ]
  61. )
  62. end
  63. end
  64. TABLES = {
  65. 1 "ResourceLose" => DiceTable::Table.new(
  66. "資源の減少チェック",
  67. "1D6",
  68. [
  69. "〈食料〉",
  70. "〈健康〉",
  71. "〈電力〉",
  72. "〈パーツ〉",
  73. "〈ヴィークル〉",
  74. "[資源の減少チェック]をもう1回行なう。その際、減少する資源は1ではなく2となる。",
  75. ]
  76. ),
  77. "ResourceGain" => DiceTable::Table.new(
  78. "獲得資源決定",
  79. "1D6",
  80. [
  81. "〈食料〉",
  82. "〈健康〉",
  83. "〈電力〉",
  84. "〈パーツ〉",
  85. "〈ヴィークル〉",
  86. "任意、好きな資源を手に入れる。",
  87. ]
  88. ),
  89. "RandomArea" => DiceTable::RangeTable.new(
  90. "都市/荒野決定",
  91. "1D6",
  92. [
  93. [1..3, "荒野エリア決定表へ( → RWaste )"],
  94. [4..6, "都市エリア決定表へ( → RUrban )"],
  95. ]
  96. ),
  97. "RandomWaste" => FiveItemsTable.new(
  98. "荒野エリア決定",
  99. "平原――地平線の果てまで続く、茫漠とした荒野。それを貫くように走るハイウェイの痕跡。その沿道に廃墟が点在している。",
  100. "砂漠――砂漠がどこまでも広がっている。大海に浮かぶ島のように、倒壊した高層ビルが顔を出している。熱と渇きが旅人を苛む。",
  101. "汚染地帯――土も、水も、空気さえも、汚染物質で満たされた区域。ここでは呼吸すらも死を招く。あまり長居したい土地ではない。",
  102. "雪原――視界一面を覆う雪の大地。ただそこにいるだけで、身体の熱が奪われていく。生命の活動を許さないモノトーンの世界だ。",
  103. "山岳――旅人の前にそびえる巨大な山塊。山越えは落石や崩落の危険性など、通過するだけでリスクが高い。だが他に道はない。"
  104. ),
  105. "RandomUrban" => FiveItemsTable.new(
  106. "都市エリア決定",
  107. "無人都市――かつて栄華を誇ったメトロポリス。だが今、旅人のほかに動いているものはいない。無数のビル群が墓標のようにそびえる。",
  108. "要塞都市――巨大な城壁と、朽ち果てた無人防衛兵器群によって守られた要塞都市。この都市が守ろうとした住人はもういない。",
  109. "地下都市――放棄された広大な地下シェルター。光の届かない暗黒の地下空間。ある時期の人類は、地下に生活拠点を移していたようだ。",
  110. "密林都市――この都市の廃墟は、繁茂したミュータント植物の密林に覆われている。そこには異形の生態系が成立している。",
  111. "水没都市――水没した都市。かつての人類の遺構群が、上昇した海面下に沈んでいる。都市の新たな主は、ミュータント魚群だ。"
  112. ),
  113. "RandomObs" => DiceTable::Table.new(
  114. "障害シーン決定",
  115. "1D6",
  116. [
  117. "技術系A( → ROTA )",
  118. "技術系B( → ROTB )",
  119. "生存系A( → ROSA )",
  120. "生存系B( → ROSB )",
  121. "戦闘系A( → ROCA )",
  122. "戦闘系B( → ROCB )",
  123. ]
  124. ),
  125. "RandomObsTechA" => FiveItemsTable.new(
  126. "ランダム障害シーン/技術系A",
  127. "電子ロック――電子ロックが生きている倉庫を発見。ロックを開けて中の資源を回収する。【技術】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら[資源の減少チェック]1回。",
  128. "発電機の再生――停止した風力発電機(風車)を発見。発電効率は低いが、復旧させればロボットのバッテリーを充電できる。【技術】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈電力〉-1。",
  129. "オーバーホール――ヴィークルが不調だ。一度しっかり分解整備(オーバーホール)しなければ。【技術】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈ヴィークル〉-1。",
  130. "リフォーム――居心地の良さそうな住居跡を発見。ちょっとリフォームすれば、快適な休息を取れる。【技術】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈健康〉-1。",
  131. "ロボット工場――ロボット工場跡を発見。残された部品をうまく加工すれば、劣化したパーツを交換できる。【技術】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈パーツ〉-1。"
  132. ),
  133. "RandomObsTechB" => FiveItemsTable.new(
  134. "ランダム障害シーン/技術系B",
  135. "悪路走破――ヴィークルで悪路を走る。スピードを落とさず走り抜ければ、時間的消耗を抑えることができる。【技術】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら[資源の減少チェック]を1回行なう。",
  136. "食料生産プラント――食料生産プラント跡を発見。うまく復旧すれば、最後に残った材料で食料を生産できる。【技術】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈食料〉-1。",
  137. "パーツ交換――ロボットのパーツが劣化、破損する。予備パーツはあるが、自力では交換が難しい。【技術】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈パーツ〉-1。",
  138. "バッテリー回収――ドローンの残骸を発見。うまく解体すれば、バッテリーを回収できそうだ。【技術】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈電力〉-1。",
  139. "ロボットの行商人――ロボットの行商人と出会う。彼は旅人たち(「数十年ぶりの客」らしい)に取り引きを持ちかけてくる。行商人の提示する品物の質を見極めろ。【技術】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0ならボッタくられ、[資源の減少チェック]を1回行なう。"
  140. ),
  141. "RandomObsSurviveA" => FiveItemsTable.new(
  142. "ランダム障害シーン/生存系A",
  143. "迷い路――入り組んだ地域を進む。方向感覚を失えば、さらなる消耗を強いられる。【生存】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら道に迷い、[資源の減少チェック]を1回行なう。",
  144. "危険地帯――ガスや汚染物質に満ちた危険地帯を通過する。ロボットはともかく、人間は長居できない。【生存】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら人間は負傷し〈健康〉-1。",
  145. "カビ――ロボットにミュータントのカビが生える。このカビは特定の貴金属を好む。すぐに除去しなければ。【生存】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈パーツ〉-1。",
  146. "水不足――水不足が深刻化し始める。一刻も早く水源を探して、補充しなければ。【生存】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈食料〉-1。",
  147. "崩壊寸前――崩れかかった遺跡から、資源を回収する。時間をかければ崩落に巻き込まれる。【生存】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら[資源の減少チェック]を1回行なう。"
  148. ),
  149. "RandomObsSurviveB" => FiveItemsTable.new(
  150. "ランダム障害シーン/生存系B",
  151. "隠れんぼ――狂暴なミュータントの群を発見。隠れてやりすごせ。【生存】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら[資源の減少チェック]を1回行なう。",
  152. "ソーラーパネル掃除――ソーラーパネルを繁茂したミュータント植物が覆っている。植物を刈り取ってパネルを復旧し、電力を得よう。【生存】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈電力〉-1。",
  153. "スタック――泥や砂地にハマって、ヴィークルがスタックする。力づくで引きずり出せ。【生存】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈ヴィークル〉-1。",
  154. "体調不良――汚染物質を吸引したか、毒に当たったか、体調が急変する。うまく療養(看病)せよ。【生存】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈健康〉-1。",
  155. "保存食の加工――食料の確保。小型の可食ミュータントを捕獲した。うまく保存用に加工せよ。【生存】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈食料〉-1。"
  156. ),
  157. "RandomObsCombatA" => FiveItemsTable.new(
  158. "ランダム障害シーン/戦闘系A",
  159. "大群との遭遇――狂暴なミュータントの群の襲撃を受ける。激しい戦闘で消耗戦となる。【戦闘】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら[資源の減少チェック]を1回行なう。",
  160. "地獄の毒々ミュータント――猛毒を持つ狂暴なミュータントが襲ってくる。うまく毒を避けて倒さなければ。【戦闘】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈健康〉-1。",
  161. "暴走ドローン――暴走ドローンを発見。ロボットと共通のパーツを使っているようだ。うまく破壊すればパーツを回収できる。【戦闘】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈パーツ〉-1。",
  162. "生体発電機――発電器官を有するミュータントに遭遇。発電器官を潰さずにしとめれば、電池代わりになるかもしれない。【戦闘】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈電力〉-1。",
  163. "高速戦闘――ヴィークル型の高速ドローンが襲ってくる。ヴィークルを破壊して部品を奪うつもりのようだ。返り討ちにして逆に部品を奪え。【戦闘】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈ヴィークル〉を1失う。"
  164. ),
  165. "RandomObsCombatB" => FiveItemsTable.new(
  166. "ランダム障害シーン/戦闘系B",
  167. "瓦礫撤去――巨大な瓦礫が進路を塞いでいる。破壊して通らなければ、遠回りを強いられ消耗する。【戦闘】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら[資源の減少チェック]を1回行なう。",
  168. "溶解ミュータント――金属や樹脂を溶かすミュータントに遭遇。執拗にロボットを狙ってくる。【戦闘】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈パーツ〉-1。",
  169. "電気食らい――電気を食う蟲型ドローンが寄ってくる。ロボットの体内にある電池は、彼らの食糧だ。【戦闘】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈電力〉-1。",
  170. "殺人機械――暴走ドローンが襲ってくる。対人殺傷用らしく、人間だけを執拗に狙ってくる。【戦闘】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈健康〉-1。",
  171. "ごちそうミュータント――大型の可食ミュータントに遭遇。貴重な食糧だ、可食部位を傷つけずに倒そう。【戦闘】の協力判定を行なう。成功数3以上なら[リワード]を1得る。成功数0なら〈食料〉-1。"
  172. ),
  173. "RandomEmo" => DiceTable::Table.new(
  174. "旅情シーン決定",
  175. "1D6",
  176. [
  177. "日常系A( → REDA )",
  178. "日常系B( → REDB )",
  179. "日常系C( → REDC )",
  180. "追憶系A( → RERA )",
  181. "追憶系B( → RERB )",
  182. "追憶系C( → RERC )",
  183. ]
  184. ),
  185. "RandomEmoDailyA" => FiveItemsTable.new(
  186. "ランダム旅情シーン/日常系A",
  187. "野営――ふたりぼっちの夜がくる。熱を失わないよう、火を焚き、寄り添う。",
  188. "暇つぶし――悪天候などにより、停滞を余儀なくされる。暇だ。とにかく暇だ。",
  189. "遊ぶ――遊ぶ。かくれんぼでも、しりとりでも、雪合戦でも、なんでもいい。まったく無意味だが、それがいい。",
  190. "訓練――いつ、どんな危険が襲ってくるか解らない。武器の扱いを訓練しよう。",
  191. "移動――ヴィークルに揺られて移動する。淡々と、黄昏の景色がゆっくりと流れていく。"
  192. ),
  193. "RandomEmoDailyB" => FiveItemsTable.new(
  194. "ランダム旅情シーン/日常系B",
  195. "食事――人間は、ものを食べなければ生きていけない。どうせいつかは死ぬのに、不便なことだ。",
  196. "観察――もうひとりの旅人を観察する。今まで知らなかった一面が見られるかもしれない。知らない方がよかったかもしれない。",
  197. "整備――ヴィークルを整備する。こいつも大事な旅の仲間だ。だが、いつかは部品や燃料が尽き、動かなくなるだろう。",
  198. "星空――星空を見上げる。世界は激変したが、星の光はほとんど変わらない。ちょっと北極星がズレたぐらいだ。",
  199. "水浴び――水場を発見。水浴びして汚れを落とす。ついでに洗濯も済ませてしまおう。どうせまた汚れるけど。"
  200. ),
  201. "RandomEmoDailyC" => FiveItemsTable.new(
  202. "ランダム旅情シーン/日常系C",
  203. "記録――日記でも、写真、スケッチ、なんでもいい。今この瞬間を、形にして残しておきたい。",
  204. "酒――なんと生きている酒蔵を発見。飲もうぜ、今宵、銀河を杯にして。ロボットが酔えるかは知らん。",
  205. "歌う――なぜかメロディーが口をついて出る。郷愁を覚える。かつて好きだった歌なのかもしれない。",
  206. "悪夢――悪夢にうなされ目が覚める。だが目覚めたこの世界が、悪夢よりマシであると言えるだろうか?",
  207. "ケンカ――ささいなことが原因で仲たがいする。セッション中に仲直りしておけ。理由は「大事なもの」を壊してしまった、などがよいだろう、"
  208. ),
  209. "RandomEmoReminiscenceA" => FiveItemsTable.new(
  210. "ランダム旅情シーン/追憶系A",
  211. "住居――住居跡を訪れる。ミイラ化した人間の死体を発見する。だいぶ前に死んだものだ。この死体はどう生き、どう死んだのだろう?",
  212. "届かなかった手紙――郵便ポストを発見する。配達されなかった手紙が残されている。恋文、借金の督促など、往時の人類の日常を垣間見る。",
  213. "ゆうえんち――娯楽施設跡(遊園地、テーマパーク)を訪れる。システムが生きており、稼働している遊具がある。少し遊んで行こう。きっと旅人は最後の客だ。",
  214. "終末ショッピング――商業施設跡(ショッピングモールなど)を訪れる。半壊した接客ロボットが現れ、何もない店内を案内する。その後「彼」は機能を停止する。",
  215. "天国なんてあるのかな――宗教施設跡(墓所や教会など)を訪れる。旅人が死んだら、誰が弔うのか? 天国はあるのか? ロボットもそこに行けるのか?"
  216. ),
  217. "RandomEmoReminiscenceB" => FiveItemsTable.new(
  218. "ランダム旅情シーン/追憶系B",
  219. "人の遺したもの――文化施設跡(博物館、図書館、美術館)を訪れる。人類が築いた文化の残滓を垣間見る。",
  220. "残骸――旅人のロボットとよく似た、別のロボットの残骸を発見する。このロボットは何のために動き、ここで力尽きたのだろう。",
  221. "飛ばない鳥――飛行場跡を訪れる。無数の航空機が擱座している。この人工の鳥たちが、ふたたび空を舞うことはないだろう。",
  222. "湯けむり終末紀行――温泉レジャー施設跡を訪れる。施設は半壊しているが、なんと未だに温泉が湧き続けている。世界が終わっても、温泉は心地よい。",
  223. "終末学校――学校の跡を訪れる。机とイスが散乱している。人間の子供たちは、ここでさまざまなことを学んだのだろう。"
  224. ),
  225. "RandomEmoReminiscenceC" => FiveItemsTable.new(
  226. "ランダム旅情シーン/追憶系C",
  227. "兵どもが夢の跡――戦場跡を通過する。動かなくなった兵器があちこちに散らばっている。彼らは何と、何のために戦ったのだろう?",
  228. "地下鉄――廃墟の地下鉄。旅人が車両に乗ると、自動制御で勝手に走り出す。次の駅に到着すると、最後まで残っていた電力が尽きる。終電だったらしい。",
  229. "謎のプラント――巨大なプラント跡を訪れる。爆発でもあったらしく、中心部が半壊している。あちこちにある表示は「ぬーくりあ」「でんじゃー」と読める。",
  230. "メリークリスマス――廃墟が、電飾や植物を模した模型で飾り立てられている。赤い服を着て袋を持ち、動物のひくソリに乗った老人の人形が置かれている。",
  231. "せめてよい夢を――完全に停止した冷凍睡眠施設を発見。眠ったまま干からびた人々がいる。旅人もこうなっていたかもしれない。その方が幸せだったかも。"
  232. ),
  233. "RandomDangerousWaste" => DiceTable::Table.new(
  234. "ランダム難所シーン/荒野系",
  235. "1D6",
  236. [
  237. "渡河( p27 )",
  238. "ワイルドレース( p27 )",
  239. "冬来たる( p27 )",
  240. "果てなき熱砂( p28 )",
  241. "鋼鉄の嵐( p28 )",
  242. "殺戮兵器、起動( p28 )",
  243. ]
  244. ),
  245. "RandomDangerousUrban" => DiceTable::Table.new(
  246. "ランダム難所シーン/都市系",
  247. "1D6",
  248. [
  249. "亀裂を超える( p29 )",
  250. "プラント復旧( p29 )",
  251. "地下迷宮( p29 )",
  252. "塔を登る( p29 )",
  253. "自動防衛システム( p30 )",
  254. "地底よりの恐怖( p30 )",
  255. ]
  256. ),
  257. }.transform_keys(&:upcase).freeze
  258. 1 ALIAS = {
  259. "RLose" => "ResourceLose",
  260. "RGain" => "ResourceGain",
  261. "RArea" => "RandomArea",
  262. "RWaste" => "RandomWaste",
  263. "RUrban" => "RandomUrban",
  264. "RObs" => "RandomObs",
  265. "ROTA" => "RandomObsTechA",
  266. "ROTB" => "RandomObsTechB",
  267. "ROSA" => "RandomObsSurviveA",
  268. "ROSB" => "RandomObsSurviveB",
  269. "ROCA" => "RandomObsCombatA",
  270. "ROCB" => "RandomObsCombatB",
  271. "REmo" => "RandomEmo",
  272. "REDA" => "RandomEmoDailyA",
  273. "REDB" => "RandomEmoDailyB",
  274. "REDC" => "RandomEmoDailyC",
  275. "RERA" => "RandomEmoReminiscenceA",
  276. "RERB" => "RandomEmoReminiscenceB",
  277. "RERC" => "RandomEmoReminiscenceC",
  278. "RDW" => "RandomDangerousWaste",
  279. "RDU" => "RandomDangerousUrban",
  280. }.transform_keys(&:upcase).transform_values(&:upcase).freeze
  281. 1 register_prefix(TABLES.keys, ALIAS.keys)
  282. end
  283. end
  284. end

lib/bcdice/game_system/Siren.rb

97.92% lines covered

80.95% branches covered

48 relevant lines. 47 lines covered and 1 lines missed.
21 total branches, 17 branches covered and 4 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/command/parser'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Siren < Base
  6. # ゲームシステムの識別子
  7. 1 ID = "Siren"
  8. # ゲームシステム名
  9. 1 NAME = "終末アイドル育成TRPG セイレーン"
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = "せいれえん"
  12. 1 HELP_MESSAGE = <<~TEXT
  13. ・判定: SL+a<=b±c
  14. a=達成値への修正(0の場合は省略)
  15. b=能力値
  16. c=判定への修正(0の場合は省略、複数可)
  17. 例)判定修正-10の装備を装着しながら【技術:60】〈兵器:2〉で判定する場合。
  18. SL+2<=60+40-10
  19. ・育成: TR$a<=b
  20. a=育成した回数
  21. b=ヘルス
  22. 例)ヘルスの現在値が60で2回目の【身体】の育成を行う場合。
  23. TR$2<=60
  24. TEXT
  25. 1 def eval_game_system_specific_command(command)
  26. 19 when: 10 case command
  27. 10 when: 9 when /^SL/ then check_action(command)
  28. 9 else: 0 when /^TR/ then check_training(command)
  29. else return nil
  30. end
  31. end
  32. 1 def check_action(command)
  33. 10 parser = Command::Parser.new('SL', round_type: @round_type).restrict_cmp_op_to(:<=)
  34. 10 parsed = parser.parse(command)
  35. 10 then: 0 else: 10 return nil if parsed.nil?
  36. 10 target = parsed.target_number
  37. 10 dice = @randomizer.roll_once(100)
  38. 10 then: 4 else: 6 if dice > target
  39. 4 return Result.failure("(1D100<=#{target}) > #{dice} > 失敗")
  40. end
  41. 6 dig10 = dice / 10
  42. 6 dig1 = dice % 10
  43. 6 then: 1 else: 5 if dig10 == 0
  44. 1 dig10 = 10
  45. end
  46. 6 then: 3 else: 3 if dig1 == 0
  47. 3 dig1 = 10
  48. end
  49. 6 achievement_value = dig10 + dig1 + parsed.modify_number
  50. 6 return Result.success("(1D100<=#{target}) > #{dice} > 成功(達成値:#{achievement_value})")
  51. end
  52. 1 def check_training(command)
  53. 9 parser = Command::Parser.new('TR', round_type: @round_type).restrict_cmp_op_to(:<=).enable_dollar.disable_modifier
  54. 9 parsed = parser.parse(command)
  55. 9 then: 0 else: 9 return nil if parsed.nil?
  56. 9 count = parsed.dollar
  57. 9 then: 0 else: 9 return nil if count.nil?
  58. 9 target = parsed.target_number
  59. 9 dice = @randomizer.roll_once(100)
  60. 9 dig10 = dice / 10
  61. 9 dig1 = dice % 10
  62. 9 then: 1 else: 8 if dig10 == 0
  63. 1 dig10 = 10
  64. end
  65. 9 then: 3 else: 6 if dig1 == 0
  66. 3 dig1 = 10
  67. end
  68. 9 achievement_value = dig10 + dig1
  69. 9 then: 5 else: 4 if dice > target
  70. 5 return Result.failure("(1D100<=#{target}) > #{dice} > 失敗(能力値減少:10 / ヘルス減少:#{achievement_value})")
  71. end
  72. 4 return Result.success("(1D100<=#{target}) > #{dice} > 成功(能力値上昇:#{count * 5 + achievement_value} / ヘルス減少:#{achievement_value})")
  73. end
  74. 1 register_prefix('SL', 'TR')
  75. end
  76. end
  77. end

lib/bcdice/game_system/Skynauts.rb

100.0% lines covered

93.33% branches covered

143 relevant lines. 143 lines covered and 0 lines missed.
30 total branches, 28 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Skynauts < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Skynauts'
  7. # ゲームシステム名
  8. 1 NAME = '歯車の塔の探空士(六畳間幻想空間)'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'はくるまのとうのすかいのおつ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ◆判定 (SNn)、(2D6<=n) n:目標値(省略時:7)
  14.  例)SN5 SN5 SN(3+2)
  15. ◆航行チェック (NV+n) n:修正値(省略時:0)
  16.  例)NV NV+1
  17. ◆ダメージチェック (Dx/y@m) x:ダメージ左側の値、y:ダメージ右側の値
  18.  m:《弾道学》(省略可)上:8、下:2、左:4、右:6
  19.  飛空艇シート外の座標は()が付きます。
  20.  例) D/4 D19/2 D/3@8 D[大揺れ]/2
  21. ◆砲撃判定+ダメージチェック (BOMn/Dx/y@m) n:目標値(省略時:7)
  22.  x:ダメージ左側の値、y:ダメージ右側の値
  23.  m:《弾道学》(省略可)上:8、下:2、左:4、右:6
  24.  例) BOM/D/4 BOM9/D19/2@4
  25. ◆《回避運動》 (AVOn@mXX) n:目標値(省略時:7)
  26.  m:回避方向。上:8、下:2、左:4、右:6、XX:ダメージチェック結果
  27.  例)
  28.  AVO9@8[縦1,横4],[縦2,横6],[縦3,横8] AVO@2[縦6,横4],[縦2,横6]
  29. MESSAGETEXT
  30. 1 register_prefix('D', '2D6<=', 'SN', 'NV', 'AVO', 'BOM')
  31. 1 def initialize(command)
  32. 47 super(command)
  33. 47 @round_type = RoundType::FLOOR # 端数切り捨て
  34. end
  35. 1 def eval_game_system_specific_command(command)
  36. 44 debug("\n=======================================\n")
  37. 44 debug("eval_game_system_specific_command command", command)
  38. 44 return get_judge_result(command) || navigation_result(command) || get_fire_result(command) ||
  39. get_bomb_result(command) || get_avoid_result(command)
  40. end
  41. 1 private
  42. 1 def get_judge_result(command)
  43. 57 else: 26 then: 31 return nil unless (m = /^2D6<=(\d)$/i.match(command) || /^SN(\d*)$/i.match(command))
  44. 26 debug("====get_judge_result====")
  45. 26 then: 9 else: 17 target = m[1].empty? ? 7 : m[1].to_i # 目標値。省略時は7
  46. 26 debug("目標値", target)
  47. 26 dice_list = @randomizer.roll_barabara(2, 6)
  48. 26 total = dice_list.sum()
  49. 26 text = "(2D6<=#{target}) > #{total}[#{dice_list.join(',')}] > #{total}"
  50. 26 then: 6 if total <= 2
  51. 6 else: 20 Result.fumble(text + " > ファンブル")
  52. 20 then: 15 elsif total <= target
  53. 15 Result.success(text + " > 成功")
  54. else: 5 else
  55. 5 Result.failure(text + " > 失敗")
  56. end
  57. end
  58. 1 def navigation_result(command)
  59. 31 else: 4 then: 27 return nil unless (m = /^NV(\+(\d+))?$/.match(command))
  60. 4 debug("====navigation_result====")
  61. 4 bonus = m[2].to_i # 〈操舵室〉の修正。GMの任意修正にも対応できるように(マイナスは無視)
  62. 4 debug("移動修正", bonus)
  63. 4 total = @randomizer.roll_once(6)
  64. 4 then: 2 else: 2 move_point_base = (total / 2) <= 0 ? 1 : (total / 2)
  65. 4 movePoint = move_point_base + bonus
  66. 4 debug("移動エリア数", movePoint)
  67. 4 Result.new("航行チェック(最低1) (1D6/2+#{bonus}) > #{total} /2+#{bonus} > #{move_point_base}+#{bonus} > #{movePoint}エリア進む")
  68. end
  69. DIRECTION_INFOS = {
  70. 1 1 => {name: "左下", position_diff: {x: -1, y: +1}},
  71. 2 => {name: "下", position_diff: {x: 0, y: +1}},
  72. 3 => {name: "右下", position_diff: {x: +1, y: +1}},
  73. 4 => {name: "左", position_diff: {x: -1, y: 0}},
  74. # 5 は中央。算出する意味がないので対象外
  75. 6 => {name: "右", position_diff: {x: +1, y: 0}},
  76. 7 => {name: "左上", position_diff: {x: -1, y: -1}},
  77. 8 => {name: "上", position_diff: {x: 0, y: -1}},
  78. 9 => {name: "右上", position_diff: {x: +1, y: -1}},
  79. }.freeze
  80. 1 def get_direction_info(direction, key, default_value = nil)
  81. 185 info = DIRECTION_INFOS[direction.to_i]
  82. 185 then: 74 else: 111 return default_value if info.nil?
  83. 111 return info[key]
  84. end
  85. 1 def get_fire_result(command)
  86. 31 else: 18 then: 13 return nil unless (m = %r{^D([12346789]*)(\[.+\])*/(\d{1,2})(@([2468]))?$}.match(command))
  87. 18 debug("====get_fire_result====")
  88. 18 fire_count = m[3].to_i # 砲撃回数
  89. 18 fire_range = m[1].to_s # 砲撃範囲
  90. 18 ballistics = m[5].to_i # 《弾道学》
  91. 18 debug("fire_count", fire_count)
  92. 18 debug("fire_range", fire_range)
  93. 18 debug("ballistics", ballistics)
  94. 18 fire_point = get_fire_point(fire_range, fire_count) # 着弾座標取得(3次元配列)
  95. 18 result = [command, get_fire_point_text(fire_point, fire_count).text] # 表示用文字列作成
  96. 18 then: 7 else: 11 if ballistics != 0 # 《弾道学》有
  97. 7 result << "《弾道学》:#{get_direction_info(ballistics, :name, '')}\n"
  98. 7 result << get_fire_point_text(fire_point, fire_count, ballistics).text
  99. end
  100. 18 Result.new(result.join(" > "))
  101. end
  102. 1 def get_fire_point(fire_range, fire_count)
  103. 18 debug("====get_fire_point====")
  104. 18 fire_point = []
  105. 18 fire_count.times do |count|
  106. 36 debug("\n砲撃回数", count + 1)
  107. 36 fire_point << []
  108. 36 y_pos = @randomizer.roll_once(6) # 縦
  109. 36 x_pos = @randomizer.roll_sum(2, 6) # 横
  110. 36 position = [x_pos, y_pos]
  111. 36 fire_point[-1] << position
  112. 36 debug("着弾点", fire_point)
  113. 36 fire_range.chars do |range_text|
  114. 38 debug("範囲", range_text)
  115. 38 position_diff = get_direction_info(range_text, :position_diff, {})
  116. 38 position = [x_pos + position_diff[:x].to_i, y_pos + position_diff[:y].to_i]
  117. 38 fire_point[-1] << position
  118. 38 debug("着弾点:範囲", fire_point)
  119. end
  120. end
  121. 18 debug("\n最終着弾点", fire_point)
  122. 18 return fire_point
  123. end
  124. 1 def get_fire_point_text(fire_point, _fire_count, direction = 0)
  125. 30 debug("====get_fire_point_text====")
  126. 30 fire_text_list = []
  127. 30 fire_point.each do |point|
  128. 67 text = ""
  129. 67 point.each do |x, y|
  130. # 《弾道学》《回避運動》などによる座標移動
  131. 135 x, y = get_move_point(x, y, direction)
  132. # マップ外の座標は括弧を付ける
  133. 135 then: 113 else: 22 text += in_map_position?(x, y) ? "[縦#{y},横#{x}]" : "([縦#{y},横#{x}])"
  134. 135 debug("着弾点テキスト", text)
  135. end
  136. 67 fire_text_list << text
  137. end
  138. 30 Result.new(fire_text_list.join(","))
  139. end
  140. 1 def in_map_position?(x, y)
  141. 135 ((1 <= y) && (y <= 6)) && ((2 <= x) && (x <= 12))
  142. end
  143. 1 def get_move_point(x, y, direction)
  144. 135 debug("====get_move_point====")
  145. 135 debug("方向", direction)
  146. 135 debug("座標移動前(x,y)", x, y)
  147. 135 position_diff = get_direction_info(direction, :position_diff, {})
  148. 135 x += position_diff[:x].to_i
  149. 135 y += position_diff[:y].to_i
  150. 135 debug("\n座標移動後(x,y)", x, y)
  151. 135 return x, y
  152. end
  153. 1 def get_bomb_result(command)
  154. 13 else: 6 then: 7 return nil unless (m = %r{^BOM(\d*)?/D([12346789]*)(\[.+\])*/(\d+)(@([2468]))?$}i.match(command))
  155. 6 debug("====get_bomb_result====", command)
  156. 6 target = m[1].to_s
  157. 6 direction = m[6].to_i
  158. 6 debug("弾道学方向", direction)
  159. 6 sn = get_judge_result("SN" + target) # 砲撃判定
  160. 6 then: 2 else: 4 if sn.failure?
  161. 2 sn.text = "#{command} > #{sn.text}"
  162. 2 return sn
  163. end
  164. # ダメージチェック部分
  165. 4 fire_command = command.slice(%r{D([12346789]*)(\[.+\])*/(\d+)(@([2468]))?})
  166. 4 sn.text = "#{command} > #{sn.text}\n > #{get_fire_result(fire_command).text}"
  167. 4 sn
  168. end
  169. 1 def get_avoid_result(command)
  170. 7 else: 7 then: 0 return nil unless (m = /^AVO(\d*)?(@([2468]))(\(?\[縦\d+,横\d+\]\)?,?)+$/.match(command))
  171. 7 debug("====get_avoid_result====", command)
  172. 7 direction = m[3].to_i
  173. 7 debug("回避方向", direction)
  174. 7 judge_command = command.slice(/^AVO(\d*)?(@([2468]))/) # 判定部分
  175. 7 sn = get_judge_result("SN" + Regexp.last_match(1).to_s)
  176. 7 then: 2 else: 5 if sn.failure?
  177. 2 sn.text = "#{judge_command} > 《回避運動》#{sn.text}"
  178. 2 return sn
  179. end
  180. 5 point_command = command.slice(/(\(?\[縦\d+,横\d+\]\)?,?)+/) # 砲撃座標
  181. 5 fire_point = scan_fire_point(point_command)
  182. 5 fire_count = fire_point.size
  183. 5 Result.success([
  184. judge_command,
  185. "《回避運動》#{sn.text}\n",
  186. point_command,
  187. "《回避運動》:" + get_direction_info(direction, :name, "") + "\n",
  188. get_fire_point_text(fire_point, fire_count, direction).text
  189. ].compact.join(" > "))
  190. end
  191. 1 def scan_fire_point(command)
  192. 5 debug("====scan_fire_point====", command)
  193. 5 command = command.gsub(/\(|\)/, "") # 正規表現が大変なので最初に括弧を外しておく
  194. 5 fire_point = []
  195. # 一組ずつに分ける("[縦y,横xの単位)
  196. 5 command.split(/\],/).each do |point_text|
  197. 16 debug("point_text", point_text)
  198. 16 fire_point << []
  199. # D以外の砲撃範囲がある時に必要
  200. 16 point_text.split(/\]/).each do |point|
  201. 36 debug("point", point)
  202. 36 fire_point[-1] << []
  203. 36 else: 36 then: 0 next unless point =~ /[^\d]*(\d+),[^\d]*(\d+)/
  204. 36 y = Regexp.last_match(1).to_i
  205. 36 x = Regexp.last_match(2).to_i
  206. 36 fire_point[-1][-1] = [x, y]
  207. 36 debug("着弾点", fire_point)
  208. end
  209. end
  210. 5 return fire_point
  211. end
  212. end
  213. end
  214. end

lib/bcdice/game_system/SkynautsBouken.rb

100.0% lines covered

91.67% branches covered

108 relevant lines. 108 lines covered and 0 lines missed.
36 total branches, 33 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/base"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class SkynautsBouken < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'SkynautsBouken'
  8. # ゲームシステム名
  9. 1 NAME = '歯車の塔の探空士(冒険企画局)'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'はくるまのとうのすかいのおつ2'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~MESSAGETEXT
  14. ・行為判定(nSNt#f) n:ダイス数(省略時2)、t:目標値(省略時7)、f:ファンブル値(省略時1)
  15. 例)SN6#2 3SN
  16. ・ダメージチェック (Dx/y@m) x:ダメージ範囲、y:攻撃回数
  17.   m:《弾道学》(省略可)上:8、下:2、左:4、右:6
  18.   例) D/4 D19/2 D/3@8 D[大揺れ]/2
  19. ・回避(AVO@mダメージ)
  20.   m:回避方向(上:8、下:2、左:4、右:6)、ダメージ:ダメージチェック結果
  21.   例)AVO@8[1,4],[2,6],[3,8] AVO@2[6,4],[2,6]
  22. ・FT ファンブル表(p76)
  23. ・NV 航行表
  24. ・航行イベント表
  25.  ・NEN 航行系
  26.  ・NEE 遭遇系
  27.  ・NEO 船内系
  28.  ・NEH 困難系
  29.  ・NEL 長旅系
  30. ■ 判定セット
  31. ・《回避運動》判定+回避(nSNt#f/AVO@ダメージ)
  32.   nSNt#f → 成功なら AVO@m
  33.   例)SN/AVO@8[1,4],[2,6],[3,8] 3SN#2/AVO@2[6,4],[2,6]
  34. ・砲撃判定+ダメージチェック (nSNt#f/Dx/y@m)
  35.   行為判定の出目変更タイミングを逃すので要GMの許可
  36.   nSNt#f → 成功なら Dx/y@m
  37.   例)SN/D/4 3SN#2/D[大揺れ]/2
  38. MESSAGETEXT
  39. 1 class << self
  40. 1 private
  41. 1 def translate_direction_infos(locale)
  42. {
  43. 2 0 => {name: "", position_diff: [0, 0]},
  44. 1 => {name: I18n.translate('SkynautsBouken.directions.lower_left', locale: locale, raise: true), position_diff: [-1, +1]},
  45. 2 => {name: I18n.translate('SkynautsBouken.directions.lower', locale: locale, raise: true), position_diff: [0, +1]},
  46. 3 => {name: I18n.translate('SkynautsBouken.directions.lower_right', locale: locale, raise: true), position_diff: [+1, +1]},
  47. 4 => {name: I18n.translate('SkynautsBouken.directions.left', locale: locale, raise: true), position_diff: [-1, 0]},
  48. 5 => {name: "", position_diff: [0, 0]},
  49. 6 => {name: I18n.translate('SkynautsBouken.directions.right', locale: locale, raise: true), position_diff: [+1, 0]},
  50. 7 => {name: I18n.translate('SkynautsBouken.directions.upper_left', locale: locale, raise: true), position_diff: [-1, -1]},
  51. 8 => {name: I18n.translate('SkynautsBouken.directions.upper', locale: locale, raise: true), position_diff: [0, -1]},
  52. 9 => {name: I18n.translate('SkynautsBouken.directions.upper_right', locale: locale, raise: true), position_diff: [+1, -1]},
  53. }.freeze
  54. end
  55. 1 def translate_tables(locale)
  56. {
  57. 2 'FT' => DiceTable::Table.from_i18n('SkynautsBouken.FumbleTable', locale),
  58. 'NV' => DiceTable::Table.from_i18n('SkynautsBouken.VoyageTable', locale),
  59. "NEN" => DiceTable::Table.from_i18n('SkynautsBouken.NavigationEventNavigationTable', locale),
  60. "NEE" => DiceTable::Table.from_i18n('SkynautsBouken.NavigationEventEncounterTable', locale),
  61. "NEO" => DiceTable::Table.from_i18n('SkynautsBouken.NavigationEventOnBoardTable', locale),
  62. "NEH" => DiceTable::Table.from_i18n('SkynautsBouken.NavigationEventHardTable', locale),
  63. "NEL" => DiceTable::Table.from_i18n('SkynautsBouken.NavigationEventLongJourneyTable', locale),
  64. }.freeze
  65. end
  66. end
  67. 1 TABLES = translate_tables(@locale)
  68. 1 register_prefix('D', '\d?SN', 'AVO', TABLES.keys)
  69. 1 def initialize(command)
  70. 54 super(command)
  71. 54 @round_type = RoundType::FLOOR # 端数切り捨て
  72. end
  73. 1 def eval_game_system_specific_command(command)
  74. 54 command_sn(command) || command_d(command) || command_avo(command) || command_snavo(command) ||
  75. command_snd(command) || roll_tables(command, self.class::TABLES)
  76. end
  77. 1 private
  78. 1 DIRECTION_INFOS = translate_direction_infos(@locale)
  79. 1 D_REGEXP = %r{^D([1-46-9]{0,8})(\[.+\]|S|F|SF|FS)?/(\d{1,2})(@([2468]))?$}.freeze
  80. 1 def command_sn(command)
  81. 62 debug("SN", command)
  82. 62 cmd = Command::Parser.new(/[1-9]?SN(\d{0,2})/, round_type: round_type)
  83. .restrict_cmp_op_to(nil)
  84. .enable_fumble.parse(command)
  85. 62 else: 20 then: 42 return nil unless cmd
  86. # [dice_count]SN[target]
  87. 20 dice_count, target = cmd.command.split("SN", 2).map(&:to_i)
  88. 20 then: 8 else: 12 dice_count = 2 if dice_count == 0
  89. 20 then: 8 else: 12 target = 7 if target == 0
  90. 20 then: 10 else: 10 fumble = cmd.fumble.nil? ? 1 : cmd.fumble
  91. 20 debug("SN Parsed", dice_count, target, fumble)
  92. 20 dice_list = @randomizer.roll_barabara(dice_count, 6)
  93. 20 dice_top_two = dice_list.sort[-2..-1]
  94. 20 then: 6 res = if dice_top_two == [6, 6]
  95. 6 else: 14 Result.critical(translate('SkynautsBouken.special'))
  96. 14 then: 6 elsif dice_list.max <= fumble
  97. 6 else: 8 Result.fumble(translate('SkynautsBouken.fumble'))
  98. 8 then: 6 elsif dice_top_two.sum >= target
  99. 6 Result.success(translate('success'))
  100. else: 2 else
  101. 2 Result.failure(translate('failure'))
  102. end
  103. 20 then: 10 if dice_count == 2
  104. 10 res.text = ["(#{dice_count}SN#{target}##{fumble})", "#{dice_top_two.sum}[#{dice_list.join(',')}]", res.text]
  105. .compact.join(" > ")
  106. else: 10 else
  107. 10 res.text = ["(#{dice_count}SN#{target}##{fumble})", "[" + dice_list.join(",") + "]", "#{dice_top_two.sum}[#{dice_top_two.join(',')}]", res.text]
  108. .compact.join(" > ")
  109. end
  110. 20 res
  111. end
  112. 1 def command_d(command)
  113. 46 m = D_REGEXP.match(command)
  114. 46 else: 8 then: 38 return nil unless m
  115. 8 fire_count = m[3].to_i # 砲撃回数
  116. 8 fire_range = m[1].to_s # 砲撃範囲
  117. 8 ballistics = m[5].to_i # 《弾道学》
  118. 8 points = get_fire_points(fire_count, fire_range)
  119. 8 command = command.sub("SF/", "[#{translate('SkynautsBouken.big_shake')},#{translate('SkynautsBouken.fire')}]/")
  120. .sub("FS/", "[#{translate('SkynautsBouken.fire')},#{translate('SkynautsBouken.big_shake')}]/")
  121. .sub("F/", "[#{translate('SkynautsBouken.fire')}]/").sub("S/", "[#{translate('SkynautsBouken.big_shake')}]/")
  122. 8 result = ["(#{command})", get_points_text(points, 0, 0)]
  123. 8 then: 4 else: 4 if ballistics != 0
  124. 4 dir = self.class::DIRECTION_INFOS[ballistics]
  125. 4 diff_x, diff_y = dir[:position_diff]
  126. 4 result[-1] += "\n"
  127. 4 result << "《#{translate('SkynautsBouken.ballistics')}》#{dir[:name]}"
  128. 4 result << get_points_text(points, diff_x, diff_y)
  129. end
  130. 8 result.compact.join(" > ")
  131. end
  132. 1 def command_avo(command)
  133. 40 debug("AVO", command)
  134. 40 dmg = command.match(/^AVO@([2468])(.*?)$/)
  135. 40 else: 6 then: 34 return nil unless dmg
  136. 6 dir = self.class::DIRECTION_INFOS[dmg[1].to_i]
  137. 6 diff_x, diff_y = dir[:position_diff]
  138. 6 "《#{translate('SkynautsBouken.avoidance')}》#{dir[:name]} > " + dmg[2].gsub(/\(?\[(\d),(\d{1,2})\]\)?/) do
  139. 18 y = Regexp.last_match(1).to_i + diff_y
  140. 18 x = Regexp.last_match(2).to_i + diff_x
  141. 18 get_xy_text(x, y)
  142. end
  143. end
  144. 1 def command_snavo(command)
  145. 34 sn, avo = command.split(%r{/?AVO}, 2)
  146. 34 debug("SNAVO", sn, avo)
  147. 34 am = /^@([2468])(.*?)$/.match(avo)
  148. 34 else: 2 then: 32 return nil unless am
  149. 2 res = command_sn(sn)
  150. 2 else: 2 then: 0 return nil unless res
  151. 2 then: 2 else: 0 if res.success?
  152. 2 res.text += "\n > " + command_avo("AVO" + avo)
  153. end
  154. 2 res
  155. end
  156. 1 def command_snd(command)
  157. 32 sn, d = command.split(%r{/?D}, 2)
  158. 32 debug("SND", sn, d)
  159. 32 m = D_REGEXP.match("D#{d}")
  160. 32 else: 6 then: 26 return nil unless m
  161. 6 res = command_sn(sn)
  162. 6 else: 6 then: 0 return nil unless res
  163. 6 then: 4 else: 2 if res.success?
  164. 4 res.text += "\n > #{command_d('D' + d)}"
  165. end
  166. 6 res
  167. end
  168. 1 def get_points_text(points, diff_x, diff_y)
  169. 12 "[#{translate('SkynautsBouken.y')},#{translate('SkynautsBouken.x')}]=" + points.map do |list|
  170. 32 list.map do |x, y|
  171. 48 get_xy_text(x + diff_x, y + diff_y)
  172. end.join()
  173. end.join(",")
  174. end
  175. # 範囲内なら[y,x]、範囲外なら([y,x])と表示
  176. 1 def get_xy_text(x, y)
  177. 66 then: 54 if (2..12).include?(x) && (1..6).include?(y)
  178. 54 "[#{y},#{x}]"
  179. else: 12 else
  180. 12 "([#{y},#{x}])"
  181. end
  182. end
  183. # 命中場所と範囲から、ダメージ位置を割り出す
  184. 1 def get_fire_points(fire_count, fire_range)
  185. 8 range = fire_range.chars.map(&:to_i)
  186. 8 fire_count.times.map do
  187. 22 y = @randomizer.roll_once(6) # 縦
  188. 22 x = @randomizer.roll_sum(2, 6) # 横
  189. 22 [[x, y]] + range.map do |r|
  190. 12 xdiff, ydiff = self.class::DIRECTION_INFOS[r][:position_diff]
  191. 12 [x + xdiff, y + ydiff]
  192. end
  193. end
  194. end
  195. end
  196. end
  197. end

lib/bcdice/game_system/SkynautsBouken_Korean.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/SkynautsBouken"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class SkynautsBouken_Korean < SkynautsBouken
  6. # ゲームシステムの識別子
  7. 1 ID = 'SkynautsBouken:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '톱니바퀴 탑의 탐공사'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:톱니바퀴 탑의 탐공사'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~MESSAGETEXT
  14. ・행위판정(nSNt#f) n:다이스 수(생략시 2), t:목표치(생략시 7), f:펌블치(생략시 1)
  15. 예)SN6#2 3SN
  16. ・대미지 체크 (Dx/y@m) x:대미지 범위、y:공격횟수
  17.   m:《탄도학》(생략 가능)상:8, 하:2, 좌:4, 우:6
  18.   예) D/4 D19/2 D/3@8 D[진동]/2
  19. ・회피(AVO@m대미지)
  20.   m:회피 방향(상:8, 하:2, 좌:4, 우:6), 대미지: 대미지 체크 결과
  21.   예)AVO@8[1,4],[2,6],[3,8] AVO@2[6,4],[2,6]
  22. ・FT 펌블표(p76)
  23. ・NV 항행표
  24. ・항행이벤트표
  25.  ・NEN 항행계
  26.  ・NEE 조우계
  27.  ・NEO 선내계
  28.  ・NEH 곤란계
  29.  ・NEL 장거리 여행계
  30. ■ 판정 세트
  31. ・《회피운동》판정+회피(nSNt#f/AVO@대미지)
  32.   nSNt#f → 성공하면 AVO@m
  33.   예)SN/AVO@8[1,4],[2,6],[3,8] 3SN#2/AVO@2[6,4],[2,6]
  34. ・포격 판정+대미지 체크 (nSNt#f/Dx/y@m)
  35.   행위 판정의 출발(出目) 변경 타이밍을 놓치므로 GM의 허가 필요
  36.   nSNt#f → 성공하면 Dx/y@m
  37.   예)SN/D/4 3SN#2/D[진동]/2
  38. MESSAGETEXT
  39. 1 def initialize(command)
  40. 27 super(command)
  41. 27 @locale = :ko_kr
  42. end
  43. 1 register_prefix_from_super_class()
  44. 1 TABLES = translate_tables(:ko_kr).freeze
  45. 1 DIRECTION_INFOS = translate_direction_infos(:ko_kr).freeze
  46. end
  47. end
  48. end

lib/bcdice/game_system/StarryDolls.rb

100.0% lines covered

100.0% branches covered

50 relevant lines. 50 lines covered and 0 lines missed.
14 total branches, 14 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/dice_table/chain_table"
  3. 1 require "bcdice/dice_table/sai_fic_skill_table"
  4. 1 require "bcdice/dice_table/table"
  5. 1 require "bcdice/format"
  6. 1 module BCDice
  7. 1 module GameSystem
  8. 1 class StarryDolls < Base
  9. # ゲームシステムの識別子
  10. 1 ID = "StarryDolls"
  11. # ゲームシステム名
  12. 1 NAME = "スタリィドール"
  13. # ゲームシステム名の読みがな
  14. 1 SORT_KEY = "すたりいとおる"
  15. # ダイスボットの使い方
  16. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  17. ・行為判定 nD6±m@s>=t
  18.  nD6の行為判定を行う。スペシャル/ファンブル/成功/失敗を判定。
  19.   n: ダイス数
  20.   m: 修正(省略可)
  21.   s: スペシャル値(省略時 12)
  22.   t: 目標値(?指定可)
  23. ・各種表
  24.  ・ランダム特技決定表 RTTn (n:分野番号、省略可能)
  25.    1願望 2元素 3星使い 4動作 5召喚 6人間性
  26.  ・ランダム分野表 RCT
  27.  ・ランダム星座表 HOR
  28.    ランダム星座表A HORA/ランダム星座表B HORB
  29.  ・主人関係表 MRT/関係属性表 RAT
  30.  ・従者関係表 SRT
  31.  ・奇跡表 MIR
  32.  ・戦果表 BRT
  33.  ・事件表 TRO
  34.  ・森事件表 TROF
  35.  ・庭園事件表 TROG
  36.  ・城内事件表 TROC
  37.  ・都市事件表 TROT
  38.  ・図書館事件表 TROL
  39.  ・駅事件表 TROS
  40.  ・従者トラブル表 TRS
  41.  ・リアクション表 忠誠 RAL
  42.  ・リアクション表 冷静 RAC
  43.  ・リアクション表 母性 RAM
  44.  ・リアクション表 年長者 RAO
  45.  ・リアクション表 無邪気 RAI
  46.  ・リアクション表 長老 RAE
  47.  ・遭遇表 ENC
  48.  ・致命傷表 FWT
  49.  ・カタストロフ表 CAT
  50.  ・回想表
  51.    〈魔術師の庭〉回想表 JDSRT/〈セブンス・ヘブン〉回想表 SHRT
  52.    /〈祝福の鐘〉回想表 BCRT/〈オメガ探偵社〉回想表 ODRT
  53.  ・出張表
  54.    〈魔術師の庭〉出張表 JDSBT/〈セブンス・ヘブン〉出張表 SHBT
  55.    /〈祝福の鐘〉出張表 BCBT/〈オメガ探偵社〉出張表 ODBT
  56.    /〈天の川商店街〉出張表 ASBT/〈ポラリス星学院〉出張表 PABT
  57.    /〈人形騎士団〉出張表 SCBT/〈人形騎士団〉への出張表 TOSCBT
  58. ・D66ダイスあり
  59. INFO_MESSAGE_TEXT
  60. 1 def initialize(command)
  61. 119 super(command)
  62. 119 @d66_sort_type = D66SortType::ASC
  63. end
  64. 1 def eval_game_system_specific_command(command)
  65. 118 action_roll(command) ||
  66. roll_tables(command, TABLES) ||
  67. RTT.roll_command(@randomizer, command)
  68. end
  69. 1 private
  70. 1 SPECIAL = "スペシャル(【星命力】を1D6点回復)"
  71. 1 FUMBLE = "ファンブル(ランダムなサインが【蝕】状態へ変化)"
  72. 1 RTT = DiceTable::SaiFicSkillTable.new(
  73. [
  74. ["願望", ["創造", "研究", "守護", "絆", "*かに座", "夢", "*しし座", "自由", "恋愛", "脚光", "世界"]],
  75. ["元素", ["光", "雷", "*ふたご座", "水", "火", "風", "木", "氷", "*おとめ座", "土", "闇"]],
  76. ["星使い", ["*おうし座", "幸運", "幻影", "テレパシー", "予知夢", "星読み", "治癒", "天候", "変身", "時間停止", "*てんびん座"]],
  77. ["動作", ["*おひつじ座", "精密", "高速", "怪力", "隠密", "飛行", "言霊", "模倣", "軽業", "歌舞", "*さそり座"]],
  78. ["召喚", ["リボン", "照明具", "*うお座", "料理", "獣", "花", "乗り物", "書物", "*いて座", "武器", "財宝"]],
  79. ["人間性", ["勇気", "知恵", "熱意", "調和", "*みずがめ座", "愛情", "*やぎ座", "センス", "根気", "礼節", "理性"]],
  80. ]
  81. )
  82. 1 def action_roll(command)
  83. 118 parser = Command::Parser.new("D6", round_type: round_type)
  84. .has_prefix_number
  85. .restrict_cmp_op_to(:>=)
  86. .enable_critical
  87. .enable_question_target
  88. 118 cmd = parser.parse(command)
  89. 118 else: 29 then: 89 return nil unless cmd
  90. 29 times = cmd.prefix_number
  91. 29 then: 1 else: 28 return nil if times < 1
  92. 28 fumble = 2
  93. 28 special = cmd.critical || 12
  94. 28 then: 1 else: 27 if special <= fumble
  95. 1 special = fumble + 1 # p.180
  96. 1 cmd.critical = special
  97. end
  98. 28 dice_list = @randomizer.roll_barabara(times, 6)
  99. 28 dice_total = dice_list.sum()
  100. 28 total = dice_total + cmd.modify_number
  101. result =
  102. 28 then: 6 if dice_total <= fumble
  103. 6 else: 22 Result.fumble(FUMBLE)
  104. 22 then: 9 elsif dice_total >= special
  105. 9 else: 13 Result.critical(SPECIAL)
  106. 13 then: 1 elsif cmd.question_target?
  107. 1 else: 12 Result.new
  108. 12 then: 6 elsif total >= cmd.target_number
  109. 6 Result.success("成功")
  110. else: 6 else
  111. 6 Result.failure("失敗")
  112. end
  113. sequence = [
  114. 28 "(#{cmd.to_s(:after_modify_number)})",
  115. "#{dice_total}[#{dice_list.join(',')}]#{Format.modifier(cmd.modify_number)}",
  116. total,
  117. result.text
  118. ].compact
  119. 28 result.text = sequence.join(" > ")
  120. 28 result
  121. end
  122. 1 HOR_TABLE_A = DiceTable::Table.new(
  123. "ランダム星座表A", # p.177
  124. "1D6",
  125. [
  126. "おひつじ座",
  127. "おうし座",
  128. "ふたご座",
  129. "かに座",
  130. "しし座",
  131. "おとめ座",
  132. ]
  133. )
  134. 1 HOR_TABLE_B = DiceTable::Table.new(
  135. "ランダム星座表B", # p.177
  136. "1D6",
  137. [
  138. "てんびん座",
  139. "さそり座",
  140. "いて座",
  141. "やぎ座",
  142. "みずがめ座",
  143. "うお座",
  144. ]
  145. )
  146. TABLES = {
  147. 1 "HORA" => HOR_TABLE_A,
  148. "HORB" => HOR_TABLE_B,
  149. "HOR" => DiceTable::ChainTable.new(
  150. "ランダム星座表", # p.177
  151. "1D6",
  152. [
  153. HOR_TABLE_A,
  154. HOR_TABLE_A,
  155. HOR_TABLE_A,
  156. HOR_TABLE_B,
  157. HOR_TABLE_B,
  158. HOR_TABLE_B,
  159. ]
  160. ),
  161. "MRT" => DiceTable::Table.new(
  162. "主人関係表", # p.186
  163. "1D6",
  164. [
  165. "親",
  166. "友人",
  167. "恩師",
  168. "相棒",
  169. "上司",
  170. "恋人",
  171. ]
  172. ),
  173. "RAT" => DiceTable::Table.new(
  174. "関係属性表", # p.186
  175. "1D6",
  176. [
  177. "尊敬/優越感",
  178. "理解/反抗",
  179. "愉快/恐怖",
  180. "友情/競争",
  181. "恋心/不気味",
  182. "庇護/劣等感",
  183. ]
  184. ),
  185. "MIR" => DiceTable::Table.new(
  186. "奇跡表", # p.177
  187. "1D6",
  188. [
  189. "空から降る一筋の光が星人形の体を包み込み、不思議な力を与えてくれる。",
  190. "守護星座に関連する人や動物が現れ、星人形に力を貸してくれる。",
  191. "運命が不自然なまでに星人形の味方をし、すべてが上手く進んでいく。",
  192. "星人形の必要とするものが空中から次々と現れる。",
  193. "少しの間だけ〈劇場〉の住人が正気に戻り、一致団結して星人形に協力してくれる。",
  194. "体中に星命力が溢れ出し、限界を超えた大規模な星術を扱えるようになる。",
  195. ]
  196. ),
  197. "BRT" => DiceTable::Table.new(
  198. "戦果表", # p.191
  199. "1D6",
  200. [
  201. "所持しているアイテムから一つを選び、同じものをもう一つ獲得する。所持していない場合はもう一度戦果表を使用する。",
  202. "時計を獲得する。",
  203. "ロザリオを獲得する。",
  204. "コンパスを獲得する。",
  205. "星の欠片を獲得する。",
  206. "自由なアイテムを一つ獲得する。",
  207. ]
  208. ),
  209. "TRO" => DiceTable::Table.new(
  210. "事件表", # p.193
  211. "2D6",
  212. [
  213. "〈変晶体〉を手にした途端、人形兵の軍勢に見つかり追われることに……! なんとかして振り切ろう!",
  214. "〈変晶体〉を乗せた物体が空を飛んでいる。接触する方法はないだろうか。",
  215. "不気味な商人が現れた。価値あるものを差し出せば、〈変晶体〉と交換してくれるという。上手く交渉しよう。",
  216. "〈変晶体〉の影響で理性を失った人々が大喧嘩をしている。これでは浄化するのも困難だ……仲間と協力して仲裁しよう。",
  217. "〈変晶体〉は建物の中にあるようだが、警備が厳重だ。どうやって侵入しようか……。",
  218. "罪のない人たちが〈変晶体〉を持つ敵に捕らわれているようだ。仲間と共に人々を助け出し、〈変晶体〉を浄化しよう。",
  219. "〈変晶体〉に操られた人々がこちらへ敵意の目を向けている。危害は加えたくないが、一体どうすれば……!",
  220. "〈変晶体〉に取り憑かれた動物が、仲間に襲いかかった! 早く助け出さなければ!",
  221. "仲間が敵にさらわれてしまった! 敵は〈変晶体〉も持っているようだ。追跡して仲間を助けなければ!",
  222. "入り組んだ場所に迷い込んでしまった。〈変晶体〉の気配は近いはずだが、どこにあるのだろう?",
  223. "〈変晶体〉は深い水の底に沈んでいるようだ。浄化する方法はないだろうか……。",
  224. ]
  225. ),
  226. "ENC" => DiceTable::Table.new(
  227. "遭遇表", # p.193
  228. "1D6",
  229. [
  230. "『弁士』コオロギのパルランテ\n指定特技: 《調和/人間性5》\n効果: プラネタリカードルール非採用時、このセッション中【運命力】を1点上昇させる。\nプラネタリカードルール採用時、ベネフィックを1枚獲得する。",
  231. "『航空士』鳩のコロンボ\n指定特技: 《熱意/人間性4》\n効果: コンパスを1つ獲得する。",
  232. "『医者』カラスのコルヴォ\n指定特技: 《礼節/人間性11》\n効果: 星の欠片を1つ獲得する。",
  233. "『御者』むく犬のメドーラ\n指定特技: 《知恵/人間性3》\n効果: 時計を1つ獲得する。",
  234. "『道化』ピエロのアルレッキーノ\n指定特技: 《センス/人間性9》\n効果: 【関係】の使用チェックをすべてはずす。使用チェックがなければ、アルレッキーノに【関係】を獲得する。",
  235. "『少女』ヤギのカプレッティーナ\n指定特技: 《愛情/人間性7》\n効果: ロザリオを1つ獲得する。",
  236. ]
  237. ),
  238. "FWT" => DiceTable::Table.new(
  239. "致命傷表", # p.184
  240. "1D6",
  241. [
  242. "敵の攻撃は星人形の瞳を直撃し、宝石は鮮血のごとく砕け散った。PCは形骸化する。",
  243. "なんとか致命傷は免れたが、もう戦闘は難しそうだ……。PCは戦闘から脱落する。",
  244. "最後の力をふり絞り、星人形は持っていたものを仲間へ投げ渡した。PCは所持しているアイテムを誰かに譲渡したのち戦闘から脱落する。",
  245. "星人形は自分の気持ちを誰かに託しながら、地面に倒れ込んだ。仲間のうち誰か一人がPCに対する【関係】を獲得したのち、PCは戦闘から脱落する。",
  246. "ただでやられるわけにはいかない……! 星人形は捨て身の攻撃を放つ。PCはエネミー1体に霧装の【耐久値】と同じダメージを与えたのち、戦闘から脱落する。",
  247. "こんなところで倒れるわけにはいかない。星人形は【星命力】1点で戦闘に復帰する。再度【星命力】が0になった場合、PCは致命傷表を使用せず戦闘から脱落する。",
  248. ]
  249. ),
  250. "CAT" => DiceTable::Table.new(
  251. "カタストロフ表", # p.198
  252. "1D6",
  253. [
  254. "〈劇場〉全体が大きく揺れ、空間に裂け目が生じる。現実は塗り替えられ……〈変容区〉と化した。最も恐れていた事態に、星人形たちは呆然と立ち尽くすほかなかった。",
  255. "激しい地鳴りと共に人形兵たちの増援が押し寄せ、形成が逆転してしまう。星人形たちはやむを得ず〈劇場〉を後にした。",
  256. "「時間切れです」戦場に〈悪魔派〉がやってきた。星座の加護は遮られ、星人形の体から力が抜けていく。「いずれまた」という声を最後に星人形の意識は途絶え……現実世界で目を覚ました。",
  257. "突如〈型堕ち〉が苦しみ始め、体に残っていた〈悪夢の霧〉を爆発させた。意識を失った星人形たちが目覚めたのは現実世界だった。……まだ再挑戦する時間はあるはずだ。",
  258. "〈型堕ち〉は自分を制御できなくなり、〈悪夢の霧〉に呑まれて姿を消してしまった。主を失った〈劇場〉は成長も衰退もしないまま、鏡の中に残り続けることになるだろう。",
  259. "〈型堕ち〉の体は膨張する〈悪夢の霧〉の圧力に耐えきれず、宝石を内側から破壊してしまった。〈型堕ち〉に残された命はあとわずかだ。星人形は〈型堕ち〉の最期を看取ることになる。",
  260. ]
  261. ),
  262. "JDSRT" => DiceTable::Table.new(
  263. "〈魔術師の庭〉回想表", # p.187
  264. "1D6",
  265. [
  266. "仕事に必要な道具が不足し、急遽買い出しへ。荷物が重くなりそうだからと、キーNPCも手伝ってくれることになった。",
  267. "キーNPCはあなたの仕事に感謝し、プレゼントを贈ってくれた。箱の中身はキーNPCのお気に入りの一品らしい。",
  268. "主人はお客さんと話し込んでいる。あなたが部屋の片隅で退屈そうにしていると、キーNPCと目が合った。",
  269. "整備作業がひと区切りついたところで、キーNPCがお茶とお菓子を持ってきてくれた。少し休憩しよう。",
  270. "整備中、星人形の体に傷が見つかった。どこで付けたのだろう? あなたはキーNPCに聞いてみることにした。",
  271. "部屋を移動中、あるものが目に留まる。それはキーNPCにとって思い出深いものであるようだ。",
  272. ]
  273. ),
  274. "SHRT" => DiceTable::Table.new(
  275. "〈セブンス・ヘブン〉回想表", # p.187
  276. "1D6",
  277. [
  278. "掃除をしていたら、お家のものを引っ掛けて壊してしまった! そこへキーNPCがやってきて……。",
  279. "キーNPCはちょっとお疲れの様子。あなたはお茶とお菓子を持って労ってあげることにした。",
  280. "料理の材料を取りたいのに、棚に手が届かない……。あなたはキーNPCに助けを求めた。",
  281. "キーNPCの仕事をお手伝い。こんな体験は初めてだ! あなたはワクワクしながら挑戦する。",
  282. "お客さんの星人形に制服を貸し出して、一緒に写真撮影をすることに。照れてるだろうか? それともノリノリ?",
  283. "今日はセブンス・ヘブンのファン感謝イベント。会場には、差し入れを持ったキーNPCの姿もあった。",
  284. ]
  285. ),
  286. "BCRT" => DiceTable::Table.new(
  287. "〈祝福の鐘〉回想表", # p.187
  288. "1D6",
  289. [
  290. "終演後のエントランスで挨拶をしていると、キーNPCが誰かと話し込んでいる。ちょっと様子を見に行こう。",
  291. "次の公演に向けて衣装合わせ。どんな役をやる? 衣装のフィット具合はどう? 確認していると、キーNPCが様子を見にやってきた。",
  292. "基礎練習。地道なルーチンワークの間、スパイスとなるのはキーNPCとのおしゃべりだ。",
  293. "学校での公演。終わったあと、子どもたちに囲まれてもみくちゃになる。キーNPCは、子どもが好きだったっけ?",
  294. "地方巡業。一緒に移動するキーNPCと、あれこれ話し込んでいると、意外な話題に移っていって……。",
  295. "撤収作業も終わりに近づくステージの上。誰もいない客席に向けて、キーNPCが遠い目をしている。",
  296. ]
  297. ),
  298. "ODRT" => DiceTable::Table.new(
  299. "〈オメガ探偵社〉回想表", # p.187
  300. "1D6",
  301. [
  302. "事件調査のため、キーNPCに聞き込み。何か有益な情報は出るだろうか。世間話になってしまうかも?",
  303. "依頼もなく平和な探偵事務所へ、キーNPCがやってきた。これが事件の序章に……なるんだろうか?",
  304. "みんなで、近所の家のペット探し。キーNPCの見知ったペットらしく、ちょっと心配そうな顔をしている。",
  305. "警察の事件調査を手伝うことに。キーNPCは、事件の重要参考人として呼び出されているようだ。",
  306. "地道な張り込み調査をしているところへ、キーNPCがやってきた。あなたに差し入れもあるようだ。",
  307. "華麗なる事件解決! 主人の推理をたくさん手伝うことができた。キーNPCも、あなたに一目置いてくれそう。",
  308. ]
  309. ),
  310. "SRT" => DiceTable::Table.new(
  311. "従者関係表", # 双子座の小径p.161
  312. "1D6",
  313. [
  314. "悪友",
  315. "きょうだい",
  316. "先輩/後輩",
  317. "相談相手",
  318. "部下/家臣",
  319. "双子",
  320. ]
  321. ),
  322. "TRS" => DiceTable::Table.new(
  323. "従者トラブル表", # 双子座の小径p.163
  324. "2D6",
  325. [
  326. "〈変晶体〉を見つけた従者は一人で「狭い場所/高い場所」へ行って戻れなくなってしまった。助けてあげよう。",
  327. "星人形の活躍に嫉妬したのか、従者が「いたずらを始めた/いじけてしまった」。友情を再確認させてあげよう。",
  328. "退屈していた従者は、ふらっとどこかへ「遊び/探索」に行ってしまった。従者の行きそうな場所を探してみよう。",
  329. "従者が「住人/PC」に一目惚れしてしまったようで、ずっと上の空だ。うまく冒険に興味を戻してあげることはできないだろうか。",
  330. "従者の姿が見えなくなったと思ったら、興味を引いた「子どもたち/小動物たち」に追い回され、奪い合いになっていた。助けてあげなければ!",
  331. "従者が〈変晶体〉に取り憑かれ、「暴れだした/逃げ出した」。なんとか取り押さえて浄化しよう!",
  332. "従者は突然、帰りたいと言い出した。「星人形が心配になった/冒険が怖くなった」ようだ……。話を聞いてあげよう。",
  333. "不注意からか、従者が何かを「壊してしまって/盗んでしまって」住人に怒られている。仲裁してあげよう。",
  334. "従者は「もっと強くなりたい/もっと美しくなりたい」と相談してきた。どう答えてあげればいいだろう?",
  335. "従者は自分の体の一部が「壊れて/汚れて」しまったことに落ち込んでいるようだ。治してあげることはできないだろうか?",
  336. "住人が従者を珍しく思い、無理やり「コレクション/商品」に加えようとしている。連れて行かれる前に救い出そう。",
  337. ]
  338. ),
  339. "RAL" => DiceTable::Table.new(
  340. "リアクション表 忠誠", # 双子座の小径p.159
  341. "1D6",
  342. [
  343. "仰せの通りに",
  344. "いえ、そのようなことは……",
  345. "我が主の判断に誤りなどございません",
  346. "ここは私が",
  347. "……ハッ! 眠ってなどおりません",
  348. "(従者の姿)の騎士として、主命を全ういたします",
  349. ]
  350. ),
  351. "RAC" => DiceTable::Table.new(
  352. "リアクション表 冷静", # 双子座の小径p.159
  353. "1D6",
  354. [
  355. "嫌な予感がするわね",
  356. "あなたがどうしたいかが大切よ",
  357. "私にはわからないわ",
  358. "気にする必要はないわ",
  359. "先を急ぎましょう",
  360. "私は(従者の姿)だけれど……あなたは本当の友達よ",
  361. ]
  362. ),
  363. "RAM" => DiceTable::Table.new(
  364. "リアクション表 母性", # 双子座の小径p.159
  365. "1D6",
  366. [
  367. "あらあら、どうしたのかしら",
  368. "頭をなでて差し上げましょう",
  369. "素晴らしいことですわ",
  370. "あなたの思う通りやっていいのですよ",
  371. "なんて愛らしい子でございましょう",
  372. "(従者の姿)の私でよければ、いっぱい甘えてくださいまし",
  373. ]
  374. ),
  375. "RAO" => DiceTable::Table.new(
  376. "リアクション表 年長者", # 双子座の小径p.159
  377. "1D6",
  378. [
  379. "大丈夫、心配しなくていいよ",
  380. "自分を信じるんだ",
  381. "フフッ、君は本当にかわいいね",
  382. "君の力はこんなものじゃないだろう?",
  383. "私にできることはそう多くない",
  384. "(従者の姿)たる私を友人に選んでくれたこと、誇りに思うよ",
  385. ]
  386. ),
  387. "RAI" => DiceTable::Table.new(
  388. "リアクション表 無邪気", # 双子座の小径p.160
  389. "1D6",
  390. [
  391. "やっちゃう~?",
  392. "楽しそうだね!",
  393. "ボクにまかせて!",
  394. "ボク、難しいことはわかんな~い",
  395. "ねえねえ、遊びに行こうよ~",
  396. "そんなこと言われても……ボク、(従者の姿)だし",
  397. ]
  398. ),
  399. "RAE" => DiceTable::Table.new(
  400. "リアクション表 長老", # 双子座の小径p.160
  401. "1D6",
  402. [
  403. "ほっほ、元気がいいのう",
  404. "どれ、ワシがやってみよう",
  405. "こりゃあたまげた",
  406. "ム? ウ、ウム、そうじゃな……",
  407. "年寄りだと思って甘く見るでないぞ",
  408. "ワシも長いこと(従者の姿)をやっとるが、こんなことは初めてじゃ",
  409. ]
  410. ),
  411. "JDSBT" => DiceTable::Table.new(
  412. "〈魔術師の庭〉出張表", # 双子座の小径p.185
  413. "1D6",
  414. [
  415. "定期点検で通っている組織が人手不足になり、協力を求められた。あなたは主人にお願いされ、手伝いをしにいくことになる。",
  416. "主人はあなたの経験になればと、しばらく別の主人の元で仕事をするよう勧めた。",
  417. "「星人形を派遣できないか」と〈魔術師の庭〉宛に相談があり、あなたは主人のお願いで出張をすることになった。",
  418. "多忙な星人形の点検をする時間が割けないクライアントに代わって、しばらくあなたが星人形たちの点検をすることになった。",
  419. "体に違和感のある星人形がいるらしい。手の空いていたあなたは、クライアントの家に滞在し様子を観察することになった。",
  420. "〈魔術師の庭〉の仕事に退屈してしまったあなたは、別の職場を体験してみることにした。",
  421. ]
  422. ),
  423. "SHBT" => DiceTable::Table.new(
  424. "〈セブンス・ヘブン〉出張表", # 双子座の小径p.185
  425. "1D6",
  426. [
  427. "以前のクライアントが人手不足になり、協力を求められた。あなたは主人にお願いされ、手伝いをしにいくことになる。",
  428. "主人の知り合いからの要望を受け、あなたは特別に派遣メイドとして通うことになった。必要ならば、仕事を手伝う場面もあるかもしれない。",
  429. "あなたはクライアントの星人形たちに家事を教えるため、しばらく出張先に滞在することになった。",
  430. "クライアントから、星人形にサプライズパーティーをしたいと相談された。あなた仕事を手伝うフリをして、星人形の下調べをすることにした。",
  431. "あなたのメイド姿が大好きなクライアントから、熱のこもった出張依頼がきた。あなたは嫌な予感を覚えながら、出張先へ向かう。",
  432. "仕事のスキルアップがしたいと思ったあなたは、一人で出張し、別の主人の元で家事を担当することになった。",
  433. ]
  434. ),
  435. "BCBT" => DiceTable::Table.new(
  436. "〈祝福の鐘〉出張表", # 双子座の小径p.185
  437. "1D6",
  438. [
  439. "いつも応援してくれている組織が人手不足になり、協力を求められた。あなたは主人にお願いされ、手伝いをしにいくことになる。",
  440. "あなたは次の役柄や脚本について研究するため、別の職場に滞在して仕事を観察することになった。",
  441. "あなたはテレビ番組や雑誌などの企画を通じて、別の職場で職業体験をすることになった。",
  442. "本番が近付き、練習時間は一刻でも惜しい。あなたは稽古場からほど近い、知り合いの家にしばらく泊めてもらうことにした。",
  443. "劇団の大ファンだという星人形(あるいは主人)の熱烈な要望があり、あなたはオフの間、出張先に滞在することになった。",
  444. "次の公演まで長期休暇をもらったあなたは、気分転換に別の主人の元で生活をすることになった。",
  445. ]
  446. ),
  447. "ODBT" => DiceTable::Table.new(
  448. "〈オメガ探偵社〉出張表", # 双子座の小径p.186
  449. "1D6",
  450. [
  451. "以前捜査協力してくれた組織が人手不足になり、協力を求められた。あなたは主人にお願いされ、手伝いをしにいくことになる。",
  452. "あなたはクライアントの周囲に起きている小さな事件の解決を依頼され、滞在しながら調査をすることになった。",
  453. "あなたはターゲットにマークされないよう、別の主人の所持する星人形を演じることになった。",
  454. "あなたの勘は、出張先の主人や星人形が怪しいと告げている……!あなたは潜り込んで調査をすることにした。",
  455. "あなたは捜査のため、事件現場からほど近い別の主人の家に滞在することにした。",
  456. "依頼が来ない……!退屈そうにしているあなたを気遣い、主人はあなたを別の主人の元で手伝わせることにした。",
  457. ]
  458. ),
  459. "ASBT" => DiceTable::Table.new(
  460. "〈天の川商店街〉出張表", # 双子座の小径p.186
  461. "1D6",
  462. [
  463. "お店の常連が人手不足になり、協力を求められた。あなたは主人にお願いされ、手伝いをしにいくことになる。",
  464. "出張先の組織が商店街のイベントに協力することになった。相手をよく知りたいと思ったあなたは、滞在しながら打ち合わせを進めることになる。",
  465. "新商品や新サービスのアイデアを求めて、あなたは他の組織へ出張することにした。",
  466. "以前出張に来てくれたお礼に、今度はあなたが出張することになった。しっかり働いて恩を返そう。",
  467. "店舗の改装に伴って、お店が長期休業に入った。あなたはその間、別の主人の元で仕事を手伝うことになる。",
  468. "お店の常連と仲良くなったあなたは、主人の計らいで出張をすることになった。楽しい思い出をたくさん作ろう。",
  469. ]
  470. ),
  471. "PABT" => DiceTable::Table.new(
  472. "〈ポラリス星学院〉出張表", # 双子座の小径p.186
  473. "1D6",
  474. [
  475. "クラスの非常勤講師が人手不足になり、協力を求められた。あなたは先生にお願いされ、手伝いをしにいくことになる。",
  476. "社会科見学の一環としてあなたは別の主人の元へ出張することになった。",
  477. "あなたは学級新聞の取材のため、別の主人の元へ出張し、情報を集めることになった。",
  478. "学校のイベントが近いのに、準備が終わらない!あなたはクラスメートの家に泊まりがけで準備を進めることになる。",
  479. "非常勤講師としてやってきた主人が気になって仕方ないあなたは、自分の主人にお願いして出張をすることになった。",
  480. "あなたは国内留学で、別の学堂へ一時的に転入することになった。新しい出会いに期待をふくらませて、あなたは出張する。",
  481. ]
  482. ),
  483. "SCBT" => DiceTable::Table.new(
  484. "〈人形騎士団〉出張表", # 双子座の小径p.187
  485. "1D6",
  486. [
  487. "知り合いの主人が人手不足になり、協力を求められた。あなたは正体を隠しつつ、手伝いをしにいくことになる。",
  488. "あなたが目を覚ますと、そこは見知らぬ組織だった。怪我をした貴方を匿ってくれいたらしい。あなたは恩返しのため、手伝いをすることになる。",
  489. "予知夢によって〈型堕ち〉の出現を知ったあなたは、夢の通り別の主人の元へ出張し、出現を待つことにした。",
  490. "あなたのアジトは襲撃を受けた。敵にアジトを特定されてしまったようだ。足取りを追われないよう、あなたはしばらく出張することになる。",
  491. "この頃戦い続きだったあなたは、他の主人の元へ出張し、気持ちをリフレッシュするよう指示された。",
  492. "主人は「自分が守っているものを知ることも大事だ」と、あなたに出張を勧めた。",
  493. ]
  494. ),
  495. "TOSCBT" => DiceTable::Table.new(
  496. "〈人形騎士団〉への出張表", # 双子座の小径p.187
  497. "1D6",
  498. [
  499. "あなたの職場が〈型堕ち〉に襲われた。主人は怪我により入院、あなたは襲撃時加勢に来た〈人形騎士団〉に匿われることになった。",
  500. "あなたは〈型堕ち〉をよく知る人物として協力を求められた。一緒に仲間を救い出そう。",
  501. "予知夢を通じて、あなたは〈人形騎士団〉に協力しなければならないと知った。",
  502. "あなたは〈人形騎士団〉の戦いを偶然目の当たりにし、共に戦いたいと感じた。彼らのように強くなりたいと願ったのかもしれない。",
  503. "〈人形騎士団〉が現れ、あなたが〈型堕ち〉に狙われていることを教えてくれた。しばらく一緒に行動した方がいいだろう。",
  504. "かつてあなたは〈人形騎士団〉と共闘し、またいつでも協力すると約束した。その約束を果たすときが来たようだ。あなたは主人に願い出る。",
  505. ]
  506. ),
  507. "TROF" => DiceTable::Table.new(
  508. "森事件表", # 双子座の小径p.191
  509. "2D6",
  510. [
  511. "〈変晶体〉に取り憑かれた食虫植物が仲間を飲み込んでしまった。早く助けなければ!",
  512. "〈変晶体〉は滝壺の中に沈んでいるようだ。しかし直接手に入れようとすれば、流れに巻き込まれて出られなくなってしまうだろう。",
  513. "鳥の巣の中に〈変晶体〉があるようだ。親鳥は雛を守ろうと警戒している。うまく心を通わせることはできないだろうか?",
  514. "巨岩の中から〈変晶体〉の気配がある……。破壊しなければ取り出すことはできないだろう。",
  515. "〈変晶体〉に憑依された小動物が、巣穴の中に入っていってしまった……。おびき寄せる方法はないだろうか?",
  516. "〈変晶体〉に憑依された動物が、仲間の大切なものを盗んでいってしまった。追いかけて取り戻そう!",
  517. "〈変晶体〉に憑依された獰猛な動物が寝息を立てている。起こさないように近づくことはできるだろうか。",
  518. "〈変晶体〉を持つ人形兵たちが車座になって、何かを相談している。幸い、相手はこちらに気付いていない。今なら……!",
  519. "仲間が落とし穴に落ちてしまった。穴の底には〈変晶体〉があるようだ。救出して浄化しよう。",
  520. "水の中を泳ぎ回る魚が〈変晶体〉を飲み込んでいるようだ。どうやって捕まえたものか……。",
  521. "崖にかかったボロボロな吊り橋の中央に〈変晶体〉を見つけた。罠だろうか。普通に取りに行けば橋が落ちてしまいそうだが……。",
  522. ]
  523. ),
  524. "TROG" => DiceTable::Table.new(
  525. "庭園事件表", # 双子座の小径p.193
  526. "2D6",
  527. [
  528. "紳士の蒐集家が、鞄の中に〈変晶体〉を入れて持ち歩いているようだ。何とか相手を傷つけず手に入れたいが、どうしようか。",
  529. "〈変晶体〉を宿した二重型が、あなたに追いかけっこを挑んできた。捕まえれば浄化できるだろうが、果たして追いつけるだろうか……?",
  530. "庭木に〈変晶体〉が憑依し、天高く伸びていく。〈変晶体〉は木の先端にあるようだが、取りにいくことはできるだろうか。",
  531. "腰を痛めてしまった老いた庭師が、「代わりに木を切ってくれたら〈変晶体〉の在り処を教えよう」と言う。手早く済ます方法は……。",
  532. "バラの茨によって雁字搦めにされ、厳重に守られた〈変晶体〉を見つけた。安全に手にする方法はあるだろうか……。",
  533. "「侵入者だ!」〈変晶体〉に取り憑かれた人形兵たちが、武器を持ってあなたに襲いかかる!",
  534. "獰猛そうな番犬が唸り声を上げ、あなたたちに敵意の眼差しを向けている。〈変晶体〉に憑依されているようだ。",
  535. "〈変晶体〉に取り憑かれた花がつるを伸ばし、一行の体を締め上げる。身動きは取れないが、脱出しなければ……!",
  536. "〈変晶体〉を取り込んだ蜂の巣から、蜂が一斉に襲いかかる!通常の攻撃では効果がなさそうだ。何か方法はないだろうか?",
  537. "上品な女性が、衣装のほつれを気にしている。修繕できれば〈変晶体〉の在り処を教えてくれるようだ。",
  538. "焼却炉の中で〈変晶体〉が燃え盛り、辺りに〈悪夢の霧〉を撒き散らしている。この激しい炎を止めないと、浄化はできそうにない。",
  539. ]
  540. ),
  541. "TROC" => DiceTable::Table.new(
  542. "城内事件表", # 双子座の小径p.195
  543. "2D6",
  544. [
  545. "「あなたには王(姫)を救うことができるのですか?」女性があなたに問いかける。あなたが力を示せば、〈変晶体〉の場所を教えるつもりのようだ。",
  546. "重くて大きな壺の中に〈変晶体〉を見つけた。壺の口は狭くて手は入りそうにない。どうやって手に入れようか……?",
  547. "敵兵の武器の装飾に〈変晶体〉が埋め込まれている。できるだけ穏便に回収したいが……。",
  548. "天井に吊るされたシャンデリアに〈変晶体〉が引っかかり、不気味な影を落としている。どうすれば手が届くだろう?",
  549. "〈型堕ち〉にそっくりな彫像を見つけた。王冠には〈変晶体〉が使われているようだ。見張り番にバレないように回収しよう。",
  550. "通路に飾られていた甲冑が突然動き出し襲いかかってきた!〈変晶体〉に操られているようだ。",
  551. "ネズミが〈変晶体〉をくわえて、壁に空いた小さな穴へ逃げていった。どうやったら捕まえられるだろう……?",
  552. "壁の向こう側から〈変晶体〉の気配がある。どこかに隠し通路があるようだが、どうすれば見つかるだろうか。",
  553. "「これよりも私に似合う装飾品を見つければ交換してやろう」貴族の男性が胸元に〈変晶体〉のブローチをつけている。",
  554. "〈変晶体〉の入った大砲が今にも着火しそうだ。早く止めなければ城外の遥か遠くまで飛ばされてしまう……!",
  555. "「助けてくれれば、〈変晶体〉の在り処を教える」手枷と足枷をかけられた星人形があなたに訴える。人形兵と違い、はっきり意識があるようだ。",
  556. ]
  557. ),
  558. "TROT" => DiceTable::Table.new(
  559. "都市事件表", # 双子座の小径p.197
  560. "2D6",
  561. [
  562. "信号が突如めちゃくちゃになって混乱が起きている。信号に〈変晶体〉が憑依しているようだ。暴走する車をかき分けて信号へ辿り着こう。",
  563. "迷子の少女が泣きながら「これあげるから、お母さんのところまで連れてって!」と妙な石を差し出す。……〈変晶体〉じゃないか!",
  564. "「そこのあんた、悪い相が出ているよ」占い師の老婆に引き止められる。手元には水晶の代わりに〈変晶体〉が……!",
  565. "〈変晶体〉を積んだ暴走トラックがあなたたちに突っ込んできた。なんとかして止めないと〈変晶体〉もろともバラバラだ!",
  566. "人混みの中に〈変晶体〉の気配を感じた。この中の誰かが持っているはずだ。しかしどうやって見つけ出そう?",
  567. "厳重な鍵がついたショーケースの中に〈変晶体〉を見つけた。何か開ける方法は……?",
  568. "「引ったくりよー!!」女性の叫び声に顔を上げると〈変晶体〉に取り憑かれた男性が逃げ去っていく!",
  569. "工事車両の荷台に瓦礫ごと〈変晶体〉が積まれている。運ばれる前に回収しなければ……。",
  570. "都市公園の水辺が黒く濁っている。中に〈変晶体〉が沈んでいるようだ。うまく見つけ出す方法はないだろうか?",
  571. "〈変晶体〉を手に入れた途端、カラスの大群が襲いかかってきた! ギラギラした〈変晶体〉を狙っているようだ。",
  572. "路上で男同士が喧嘩をしているが、様子がおかしい。殴りかかろうとする男の手には〈変晶体〉が! 喧嘩を仲裁して〈変晶体〉を手に入れよう。",
  573. ]
  574. ),
  575. "TROL" => DiceTable::Table.new(
  576. "図書館事件表", # 双子座の小径p.199
  577. "2D6",
  578. [
  579. "本棚に誰かの日記が混ざっているのを見つけた。中には「邪悪な黒い宝石を入手した」とある。持ち主を見つければ、〈変晶体〉が手に入るかもしれない。",
  580. "「探しているものが見つかる本」を発見した。文字もページもかなり多い本だが、〈変晶体〉の場所が書かれたページを見つけられただろうか……?",
  581. "館員が〈変晶体〉のありかを教えてくれたが、道案内の内容がかなり複雑だ……。どうにかしてたどり着く方法は……。",
  582. "本が積み上がってできた巨大な山の中から、〈変晶体〉の気配がある。なんとかして山をどかすことはできないだろうか。",
  583. "本に触れた途端〈悪夢の霧〉が吹き出し、視界を奪われる。真っ暗で何も見えないが、はやく〈変晶体〉の影響を受けた本を見つけよう。",
  584. "〈変晶体〉を見つけた直後、巨大な本棚が倒れてきた。このままでは〈変晶体〉を手に入れる前に全員下敷きになってしまう……!",
  585. "絵本を開くと、お話の登場人物が飛び出して襲いかかってきた。相手は〈変晶体〉に取り憑かれているようだ。",
  586. "〈変晶体〉の宿った本を、二人の人形兵が見張っている。うまく彼らの注意を引けないだろうか……?",
  587. "本棚の一番上の列に〈変晶体〉が挟まっているが、はしごなどは見当たらない。よじ登るしかないのだろうか……?",
  588. "あなたは〈変晶体〉を手に入れたが、二重型に奪われてしまう。「知らないお話を聞かせてくれたら返してあげる」と二重型は言うが……。",
  589. "「ご本を読んでくださらない?」少女は〈悪夢の霧〉で黒く澱んだ本を抱えて言う。願いを叶えなければ〈変晶体〉が潜んだ本は離してもらえなさそうだ。",
  590. ]
  591. ),
  592. "TROS" => DiceTable::Table.new(
  593. "駅事件表", # 双子座の小径p.201
  594. "2D6",
  595. [
  596. "「旅行キャンペーンお申し込みの方には〈変晶体〉プレゼント!」と書かれた張り紙を見つける。誰かの手に渡る前に回収しよう!",
  597. "落とし物を探している老人に出会う。見つけられたら〈変晶体〉と交換してくれるようだ。",
  598. "改札の向こうに〈変晶体〉を見つけたが、「切符がないと通れませんよ」と止められる。でも切符売り場も見つからないし、どうやって通ろうか……。",
  599. "複数の鳩が〈変晶体〉をつついて遊んでいる。鳩に〈変晶体〉の影響が出る前に回収しよう。",
  600. "「なんだこれは?」駅員達が〈変晶体〉を囲んで首を傾げている。なんとか説得して〈変晶体〉を渡してもらおう。",
  601. "線路上に〈変晶体〉が落ちているが、もうすぐ列車がやってくる!列車が通過したあと、元の場所にあるかはわからない……!",
  602. "〈変晶体〉を持った人形兵たちはあなたたちを追っていたが、人混みで見失ったようだ。うまく利用客に紛れれば、戦わずに浄化できるかもしれない。",
  603. "停車中の電車が〈悪夢の霧〉に包まれ、乗客はパニックになっている。あの中に〈変晶体〉があるはずだ。しかしまずは乗客を救出しよう。",
  604. "〈変晶体〉を宿した二重型があなたを線路に突き落とそうとぶつかってきた。どうにかこの場を乗り切って二重型を捕まえよう!",
  605. "時刻表「〈変晶体〉の列車」と表示される。〈変晶体〉に憑依された列車が通過するようだ。列車を止めることなんてできるのだろうか……!?",
  606. "路上コンサートの観客達の様子がおかしい。よく見ると演奏者の楽器に〈変晶体〉が埋め込まれている!早く浄化してみんなの目を覚まそう。",
  607. ]
  608. ),
  609. }.freeze
  610. 1 register_prefix('\d+D6', RTT.prefixes, TABLES.keys)
  611. end
  612. end
  613. end

lib/bcdice/game_system/SteamPunkers.rb

95.12% lines covered

85.71% branches covered

41 relevant lines. 39 lines covered and 2 lines missed.
14 total branches, 12 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/base'
  3. 1 require 'bcdice/dice_table/d66_range_table'
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class SteamPunkers < Base
  7. 1 ID = 'SteamPunkers'
  8. 1 NAME = 'スチームパンカーズ'
  9. 1 SORT_KEY = 'すちいむはんかあす'
  10. 1 HELP_MESSAGE = <<~MESSAGETEXT
  11. ・判定コマンド (SPn)
  12. SP(判定ダイス数)>=(目標値)
  13. SP4>=3のように入力し、5が出たらヒット数1,6が出たらヒット数2として成功数を数えます。
  14. ≪スチームパンク!≫による振り直しのため、出力には失敗ダイス数を表示します。
  15. 目標値は省略可能です。
  16. 例:(SP4>=3) > [3,4,1,6] > 成功数:2, 失敗数:3 > 失敗
  17. 例:(SP4) > [3,4,1,6] > 成功数:2, 失敗数:3
  18. ・表
  19. ・プロフ(Profile):年齢表 PAT, 性別表 PST, 国籍表 PCT
  20. ・名前表(Name):イギリス NIT, アメリカ NAT, フランス NFT, ドイツ NGT, ソビエト NST, 日本表 NJT
  21. ・過去表(Past):トゥルース PTT, ガーディアン PGT, ノーブル PNT, デヴォート PDT, エセティック PET, チャレンジ PACT
  22. ・経緯表(Background):ギガントアームズ BGT, アーマードリム BAT, エッジモービル BET, クロノウェポン BCT, スパイテック BST, スチームウェア BWT
  23. ・特徴表(Feature):特徴表S FST, 特徴表P FPT
  24. ・関係性表(Relationship):関係性表S RST, 関係性表P RPT
  25. ・感情表(Emotion):感情表S EST, 感情表P EPT
  26. ・その他(Other);災厄表 ODT, 場面表 OST, 交流表 OIT, 激憤表 OFT
  27. MESSAGETEXT
  28. 1 def eval_game_system_specific_command(command)
  29. 71 result = roll_tables(command, TABLES)
  30. 71 then: 62 else: 9 return result if result
  31. 9 return roll_sp(command)
  32. end
  33. 1 def roll_sp(command)
  34. 9 m = /^SP(\d+)(?:>=(\d+))?$/i.match(command)
  35. 9 else: 9 then: 0 unless m
  36. return nil
  37. end
  38. 9 dice_count = m[1].to_i
  39. 9 then: 6 else: 3 target_number = m[2]&.to_i
  40. 9 dice_list = @randomizer.roll_barabara(dice_count, 6)
  41. 9 dice_list_text = dice_list.join(',')
  42. 9 successes = dice_list.count(6) * 2 + dice_list.count(5)
  43. 59 failures = dice_list.count { |x| x <= 4 }
  44. result =
  45. 26 then: 2 if dice_list.all? { |x| x == 1 }
  46. 2 else: 7 Result.fumble("ファンブル")
  47. 7 then: 5 elsif target_number
  48. 5 then: 2 else: 3 successes >= target_number ? Result.success("成功") : Result.failure("失敗")
  49. else: 2 else
  50. 2 Result.new
  51. end
  52. 9 result.text = [
  53. "(#{command})",
  54. "[#{dice_list_text}]",
  55. "成功数:#{successes}, 失敗数:#{failures}",
  56. result.text
  57. ].compact.join(" > ")
  58. 9 result.critical = dice_list.include?(6)
  59. 9 return result
  60. end
  61. # スチームパンカーズ用のテーブル
  62. 1 class SPTable < DiceTable::D66RangeTable
  63. # @param name [String]
  64. # @param items [Array<String>]
  65. 1 def initialize(name, items)
  66. 31 then: 0 else: 31 if items.size != RANGE.size
  67. raise UnexpectedTableSize.new(name, items.size)
  68. end
  69. 31 items_with_range = RANGE.zip(items)
  70. 31 super(name, items_with_range)
  71. end
  72. # 23..32 と 61..66 が6パターン分
  73. # その他が4パターン分
  74. 1 RANGE = [11..14, 15..22, 23..32, 33..36, 41..44, 45..52, 53..56, 61..66].freeze
  75. end
  76. 1 class UnexpectedTableSize < StandardError; end
  77. TABLES = {
  78. 1 "PAT" => SPTable.new(
  79. "年齢表",
  80. [
  81. "【14~15歳】 まだまだ、子ども扱い。また、過去の内容は父か母のことを指している。",
  82. "【16~17歳】 そろそろ成人として扱われる。また、過去の内容は父か母のことを指している。",
  83. "【18~19歳】 職場では修行期間中である。また、過去の内容は両親のことか、あなた自身のことだ。",
  84. "【20~21歳】 ようやく一人前の年齢である。また、過去の内容は両親のことか、あなた自身のことだ",
  85. "【22~23歳】 働き盛りである。また、過去の内容はあなた自身のことだ。",
  86. "【24~25歳】 働き盛りである。また、過去の内容はあなた自身のことだ。",
  87. "【26~27歳】 かつて、従軍した可能性がある。また、過去の内容はあなた自身のことだ。",
  88. "【28~30歳】 蒸気大戦末期をよく知っている。また、過去の内容はあなた自身のことだ。"
  89. ]
  90. ),
  91. "PST" => SPTable.new(
  92. "性別表",
  93. [
  94. "【男性】 背が高く、がっしりしている。",
  95. "【女性】 蠱惑的な身体をしている。",
  96. "【男性】 平均的な中肉中背である。",
  97. "【女性】 女性らしい体形をしている。",
  98. "【男性】 近世の取れた肉体をしている。",
  99. "【女性】 彫刻のように美しい体形である。",
  100. "【男性】 一見すると細身に見える。",
  101. "【女性】 スリムな体形をしている。"
  102. ]
  103. ),
  104. "PCT" => SPTable.new(
  105. "国籍表",
  106. [
  107. "【日本皇国】 あなたは日本人である。",
  108. "【フランス共和国】 あなたはフランス人である。",
  109. "【アメリカ合衆国】 あなたはアメリカ人である。",
  110. "【イギリス王国】 あなたはイギリス人である。",
  111. "【イギリス王国】 あなたはイギリス人である。",
  112. "【イギリス王国】 あなたはイギリス人である。",
  113. "【ドイツ帝国】 あなたはドイツ人である。",
  114. "【ソビエト連邦】 あなたはソビエト人である。"
  115. ]
  116. ),
  117. "NIT" => SPTable.new(
  118. "名前表・イギリス(男性名/女性名/名字)",
  119. [
  120. "アーロン/アビゲイル/アダム",
  121. "カラム/オーレリア/バーナード",
  122. "クライヴ/ブレンダ/ビーチャム",
  123. "カーティス/キャロライン/ビリンガム",
  124. "ダンカン/クリス/ボイド",
  125. "アイオン/イーニッド/クロムウェル",
  126. "ネイサン/グレイス/エアハート",
  127. "ウィリアム/ローレンシア/ハックワース"
  128. ]
  129. ),
  130. "NAT" => SPTable.new(
  131. "名前表・アメリカ(男性名/女性名/名字)",
  132. [
  133. "ジェラルド/デイジー/キャンベル",
  134. "クラーク/ベアトリス/ベックフォード",
  135. "ヴィクター/ケイト/ガードナー",
  136. "ザック/ルシール/キンケイド",
  137. "ヘクター/エレイン/コールリッジ",
  138. "アーサー/アンジェリカ/アレクサンダー",
  139. "アドニス/アルダ/オースティン",
  140. "ランバート/イヴ/デビットソン"
  141. ]
  142. ),
  143. "NFT" => SPTable.new(
  144. "名前表・フランス(男性名/女性名/名字)",
  145. [
  146. "ベルナール/ベアトリス/バシュラール",
  147. "セドリック/セシリア/ベルモンド",
  148. "エルネスト/コレット/ボニツェール",
  149. "フレデリック/エルザ/ボワイエ",
  150. "ロランド/リュクレース/ディノワール",
  151. "イアサント/アンリエット/シャルトー",
  152. "バスティアン/ブリジット/オードラン",
  153. "ルイ/リリアーヌ/ドラクランジュ"
  154. ]
  155. ),
  156. "NGT" => SPTable.new(
  157. "名前表・ドイツ(男性名/女性名/名字)",
  158. [
  159. "アルベルト/アデーレ/アッカーマン",
  160. "バシリウス/アルマ/バルツァー",
  161. "ブルーノ/クリステル/ビットナー",
  162. "エトムント/エルネスタ/コルネリウス",
  163. "ゴッツ/クラリッサ/アイヒマン",
  164. "ヨハン/モニカ/フリードリヒ",
  165. "レオンハルト/オクタヴィア/ハイセルタ",
  166. "ブルクハルト/クロジンデ/ビンデバルト"
  167. ]
  168. ),
  169. "NST" => SPTable.new(
  170. "名前表・ソビエト(男性名/女性名/名字)",
  171. [
  172. "イリイチ/バルバラ/バビチェフ",
  173. "ミハイル/ジナイーダ/ボブロフ",
  174. "セルゲイ/クラーラ/ヴォルコフ",
  175. "イヴァン/レイラ/ガボエフ",
  176. "アラン/オルガ/ジェミチェフ",
  177. "ボリス/ナタリヤ/ドミトリエフ",
  178. "ウラジミル/ソフィア/エルマコフ",
  179. "アレクセイ/マルタ/ダンチェンコ"
  180. ]
  181. ),
  182. "NJT" => SPTable.new(
  183. "名前表・日本(男性名/女性名/名字)",
  184. [
  185. "タキジ/タキ/トウドウ",
  186. "シンヤ/アヤ/マツモト",
  187. "レイジ/カオルコ/サガラ",
  188. "コウタロウ/セン/オオシマ",
  189. "ヒロシ/チサ/クジョウ",
  190. "ジロウ/カナ/ヤマガタ",
  191. "マサヒト/マイ/イトウ",
  192. "ショウジ/アヤメ/シンドウ"
  193. ]
  194. ),
  195. "PTT" => SPTable.new(
  196. "過去表『トゥルース』",
  197. [
  198. "【決着】 あなたは怨敵である蒸気事件の犯人を追っている。いつの日か、そいつとは決着をつけるつもりだ。",
  199. "【陰謀】 とある陰謀により、あなたは故郷、あるいはかつての地位を失ってしまった。",
  200. "【後悔】 ある蒸気事件を解決できなかった。結果、あなたは大切な人を失ってしまった。",
  201. "【失踪】 かつて、あなたが愛した人は不自然な失踪を遂げてしまった。あの人はいったいどこへ……?",
  202. "【冤罪】 ある陰謀により、あなたは冤罪をかけられ、かつての地位を追われてしまった。",
  203. "【裏切り】 とある蒸気事件の際に無二の親友があなたを裏切り、理由も告げぬまま消え去った。",
  204. "【誓い】 とある陰謀により、あなたは大切な何かを失った。いつか陰謀を暴く……それがあなたの誓いだ。",
  205. "【喪失】 とある蒸気事件の際、あなたの家族は何者かの手により惨殺された。犯人は今も見つかっていない。"
  206. ]
  207. ),
  208. "PGT" => SPTable.new(
  209. "過去表『ガーディアン』",
  210. [
  211. "【後悔】 ある蒸気事件を解決できなかった。結果、あなたは大切な人を失ってしまった。",
  212. "【贖罪】 あなたは過去に罪なき人々の虐殺を強制させられた。だから、贖罪のために人々を護っている。",
  213. "【無力】 かつて、あなたは無力だった。そして、無力ゆえに大切な人を護ることができなかった。",
  214. "【憧れ】 あなたの憧れた人は、いつだって弱者の味方だった。そして、あなたはあの人の背中を追い続けている。",
  215. "【使命】 弱き者たちの盾となる。それが生まれたときから、あなたに課せられ唯一の使命だった。",
  216. "【見殺し】 あなたはやむを得ない事情により、仲間を見殺しにしてしまった。だから、次は絶対見殺しにしない。",
  217. "【死別】 とある事件の際、あなたは家族を護りきれず失ってしまった。だから……今度こそ護ってみせる。",
  218. "【庇護】 現在、あなたには護るべき人、護るべき場所がある。それらの日常を護るべく、あなたは戦ったいる。"
  219. ]
  220. ),
  221. "PNT" => SPTable.new(
  222. "過去表『ノーブル』",
  223. [
  224. "【復讐】 あなたの家族は蒸気事件の犠牲となった。ゆえに、あなたは家族の仇を討つべく犯人を捜している。",
  225. "【理不尽】 あなたは幼少期に、心優しかった使用人が理不尽な虐待の末に殺害される場面を目撃してしまった。",
  226. "【反発】 あなたの親は悪徳を重ねる権力者だった。そんな親が嫌いで、あなたは常に反発していた。",
  227. "【高貴】 あなたは生来から高貴な信念の持ち主だ。それゆえ弱者を救い、導くことに疑問はない。",
  228. "【偽物】 あなたは貴族の影武者を務める元平民だ。しかし、演じるうちに、あなたは真の高貴を身に着けた。",
  229. "【悲恋】 あなたは、下層市民と身分違いの恋をした。だが、愛する人は蒸気事件の犠牲者となった。",
  230. "【権謀】 あなたの両親は、とある権力闘争に巻き込まれた際、不自然な蒸気事件に遭遇して命を落とした。",
  231. "【慈愛】 あなたは、真の貴族であった両親から他者を慈しむことは当然だと教育された。"
  232. ]
  233. ),
  234. "PDT" => SPTable.new(
  235. "過去表『デヴォート』",
  236. [
  237. "【忠義】 あなたは、忠義の大切さを教えられて育ってきた。それゆえ、あなたは主に忠誠をささげるのだ。",
  238. "【忠臣】 あなたは国や組織に仕える忠臣だった。だが、権力闘争によって追われ、今は市井に身を潜めている。",
  239. "【恩義】 あなたは現在の主たる人物、または組織に救われた。いつの日か、この恩に報いなければ。",
  240. "【無心】 あなたは生来より、主や組織に仕える教育を受けてきた。ゆえに、忠義を尽くすことに疑問はない。",
  241. "【心酔】 あなたは現在の主や組織に心酔している。だから、主や組織のために蒸気事件に立ち向かう",
  242. "【復習】 あなたの主は邪悪な蒸気事件の犠牲となった。以後、あなたは主の仇を討つべく犯人を捜している。",
  243. "【約束】 あなたの主は蒸気事件の犠牲者だ。主を看取る際、あなたは世界から蒸気事件を一掃すると約束した。",
  244. "【犠牲】 あなたには尊敬に値する主がいた。だが、その主はあなたを庇って、邪悪な陰謀の犠牲となった。"
  245. ]
  246. ),
  247. "PET" => SPTable.new(
  248. "過去表『エセティック』",
  249. [
  250. "【研究】 あなたは蒸気犯罪で用いられるスチームギアを撲滅するために、常に研究を続けている。",
  251. "【悪用】 あなたは過去に自らが製造した、あるいは所有するスチームギアが悪用され、憤慨したことがある。",
  252. "【仁義】 あなた、仁義の大切さを教えられて育ってきた。それゆえ、あなたは虐げられる物たちを救うのだ。",
  253. "【美意識】 あなたは、スチームギアが犯罪に用いられる場面を目撃した際、吐き気がするほど醜いと感じた。",
  254. "【正義】 あなたは蒸気事件の元犠牲者だ。あなたは、自らの正義を成すために今も蒸気事件に挑み続けている。",
  255. "【正論】 あなたは昔から、スチームギアが正しい方法で利用されないことが我慢ならない。",
  256. "【天誅】 あなたは蒸気事件によって、全てを失ってしまった。だから、蒸気事件を起こす黒幕が許せない。",
  257. "【報復】 あなたの恩師は過去に蒸気事件で犠牲となっている。あなたはいつか、その犯人に報復するつもりだ。"
  258. ]
  259. ),
  260. "PACT" => SPTable.new(
  261. "過去表『チャレンジ』",
  262. [
  263. "【誓い】 とある陰謀により、あなたは大切な何かを失った。いつか陰謀を暴く……それがあなたの誓いだ。",
  264. "【研究】 あなたは蒸気犯罪で用いられるスチームギアを撲滅するために、常に研究を続けている。",
  265. "【反抗】 あなたは夢や努力を嘲笑されて育った。そのせいか、人々を虐げる蒸気事件が我慢ならない。",
  266. "【克服】 あなたは恐ろしい蒸気事件に遭遇した過去がある。その恐怖を克服するため、蒸気事件に挑むのだ。",
  267. "【修練】 あなたは修練により、己を高める術を知っている。そして修練のため、蒸気事件に挑むのだ。",
  268. "【挑戦】 あなたは幼少時から困難に立ち向かい続けてきた。ゆえに、蒸気事件であろうと立ち向かうのだ。",
  269. "【決着】 あなたは怨敵である蒸気事件の犯人を追っている。いつの日か、そいつとは決着をつけるつもりだ。",
  270. "【異質】 あなたは困難に立ち向かうことでしか高揚できない。そして、蒸気事件以上の困難など存在しないのだ。"
  271. ]
  272. ),
  273. "BGT" => SPTable.new(
  274. "経緯表『ギガントアームズ』",
  275. [
  276. "【元近衛兵】 あなたは上層部の警護を任されていた元近衛兵で、スチームギアは大戦時に入手したものである。",
  277. "【反逆者の子】 スチームギアは、スチームパンカーだったあなたの亡父が使っていた形見である。",
  278. "【元殺し屋】 あなたは、かつて殺し屋だった。このスチームギアは以前の仕事の報酬として受け取ったものだ。",
  279. "【元傭兵】 あなたは蒸気大戦で荒稼ぎしていた元傭兵で、このスチームギアは大戦時に入手したものだ。",
  280. "【元英雄】 あなたは蒸気大戦の英雄だ。あなたは戦線に赴く際、上層部から新世代スチームギアを支給されたのだ。",
  281. "【元軍人】 あなたは蒸気大戦にも従軍した元軍人で、大戦時にスチームギアを入手した。",
  282. "【元特殊部隊】 あなたは蒸気大戦で活躍した元特殊部隊員で、大戦時にスチームギアを入手した。",
  283. "【戦場帰り】 あなたは蒸気大戦に従軍した経験を持つ戦場帰りで、大戦時にスチームギアを入手した。"
  284. ]
  285. ),
  286. "BAT" => SPTable.new(
  287. "経緯表『アーマードリム』",
  288. [
  289. "【試験操縦士】 あなたは軍や企業で試験操縦士を務めており、その折に、スチームギアを密かに入手した。",
  290. "【闇取引】 あなたは闇取引のコネクションがあり、そのコネを利用してスチームギアを入手した。",
  291. "【貴族出身】 あなたは貴族、あるいは元貴族だ。スチームギアは、屋敷の倉にあった品を改造したものである。",
  292. "【元研究者】 あなたはスチームギアの元研究者で、自らの肉体を防護するためにスチームギアを開発した。",
  293. "【戦場帰り】 あなたは蒸気大戦に従軍した経験を持つ戦場帰りで、大戦時にスチームギアを入手した。",
  294. "【謎の協力者】 あなたが蒸気事件に立ち向かおうとした際、謎の協力者が現れ、スチームギアを与えてくれた。",
  295. "【元修理屋】 あなたは元修理屋だ。スチームギアはジャンク置き場で偶然見かけたものをレストアしたものだ。",
  296. "【簒奪者】 あなたは蒸気事件に巻き込まれた際、偶然と幸運が重なり、相手のスチームギアを奪取できた。"
  297. ]
  298. ),
  299. "BET" => SPTable.new(
  300. "経緯表『エッジモービル』",
  301. [
  302. "【車泥棒】 あなたは元車泥棒だ。このスチームギアは出所不明のものをちょろまかしたものだ。",
  303. "【元機関工】 あなたは優れた技術を持つ元機関工で、出所不明のスチームギアを偶然にも入手した。",
  304. "【元エース】 あなたは蒸気大戦時に英雄と呼ばれた元操縦士で、大戦時にスチームギアを入手した。",
  305. "【元輸送兵】 あなたは蒸気大戦に従軍した経験を持つ元輸送兵で、大戦時にスチームギアを入手した。",
  306. "【蒸気工の子】 あなたは蒸気工、あるいは蒸気技術者の子供だった。スチームギアは、両親が所有していたものである。",
  307. "【元レーサー】 あなたは蒸気車両のレースに出場していたレーサーで、スチームギアは偶然にも入手したものだ。",
  308. "【違法改造屋】 あなたはかつて、違法で改造を施すモグリの機関工だった。スチームギアは、その際に入手したものだ。",
  309. "【逃亡兵】 あなたは、戦場から逃げ出した逃亡兵だ。スチームギアは戦場に赴く際に支給された試作機である。"
  310. ]
  311. ),
  312. "BCT" => SPTable.new(
  313. "経緯表『クロノウェポン』",
  314. [
  315. "【元武器商人】 あなたは蒸気大戦時にスチームギアを販売していた元武器商人、あるいはその護衛だ。",
  316. "【元製造者】 あなたは蒸気大戦時にスチームギアを製造していた。そして、身を護るために自身の手で製造したのだ。",
  317. "【反逆者の子】 スチームギアは、スチームパンカーだったあなたの亡父が使っていた形見である。",
  318. "【元近衛兵】 あなたは上層部の警護を任されていた元近衛兵で、スチームギアは大戦時に入手したものである。",
  319. "【元特殊部隊】 あなたは蒸気大戦で活躍した元特殊部隊員で、大戦時にスチームギアを入手した。",
  320. "【元傭兵】 あなたは蒸気大戦で荒稼ぎしていた元傭兵で、このスチームギアは大戦時に入手したものだ。",
  321. "【裏稼業】 あなたはかつて裏稼業に手を染めていた荒事屋で、スチームギアは、かつての仕事の報酬である。",
  322. "【元英雄】 あなたは蒸気大戦の英雄だ。あなたは戦線に赴く際、上層部から新世代スチームギアを支給されたのだ。"
  323. ]
  324. ),
  325. "BST" => SPTable.new(
  326. "経緯表『スパイテック』",
  327. [
  328. "【元刑事】 あなたは、蒸気事件ばかりを追っていた元刑事だ。スチームギアは犯罪者から奪い取ったものである。",
  329. "【元結社の一員】 あなたは邪悪な秘密結社に所属していた元工作員だ。スチームギアはその頃に支給されたものである。",
  330. "【研究者の肉親】 あなたの肉親が軍の研究者で、彼らが試作機として制作したものを偶然入手した。",
  331. "【元工作員】 あなたは、蒸気大戦の裏側で活躍した元工作員で、大戦終結と同時に、そのスチームギアを入手した。",
  332. "【元諜報員】 あなたは蒸気大戦の際に活躍した元スパイで、当時支給されたスチームギアを私物化している。",
  333. "【後援者】 あなたが行なう蒸気事件の調査を援助する者がいる。彼は、このスチームギアを制作した人物である。",
  334. "【元暗殺部隊】 あなたは、蒸気大戦時に暗躍した元暗殺部隊員で、スチームギアはその頃に入手したものだ。",
  335. "【元盗人】 あなたは盗品として流れてきたスチームギアを偶然発見して、入手した。"
  336. ]
  337. ),
  338. "BWT" => SPTable.new(
  339. "経緯表『スチームウェア』",
  340. [
  341. "【独自ルート】 あなたは人間の限界を超えるために、独自のルートを使って、自らの意志で肉体を機械化した。",
  342. "【相棒の技師】 あなたが蒸気事件で肉体を欠損した際、機械技師をしている相棒が欠損部位を機械化してくれた。",
  343. "【元実験体】 あなたは蒸気事件で重傷を負った際、実験体となる代わりに特殊な機械化手術を施された。",
  344. "【元機械化兵】 あなたは大戦時に機械化手術で蘇った元蒸気兵だ。終戦後、スチームギアをわざと取り換えなかった。",
  345. "【帰還兵】 あなたは蒸気大戦から帰還した帰還兵だ。だが戦時中に肉体が欠損し、軍部が機械化してくれた。",
  346. "【元機械闘士】 あなたは機械化格闘に出場した元格闘士だ。機械化した部位は、その頃に違法改造したものだ。",
  347. "【元闇医者】 あなたは、元モグリの機械医師だった。機械化したその部位は、その頃に自身で改造したものだ。",
  348. "【元英雄】 あなたは蒸気大戦の英雄だ。あなたは戦線に赴く際、上層部から新世代スチームギアを支給されたのだ。"
  349. ]
  350. ),
  351. "FST" => SPTable.new(
  352. "特徴表S",
  353. [
  354. "【蒸気帽】 あなたは、なんらかの蒸気機械を仕込んだ帽子を愛用している。",
  355. "【装飾品】 あなたは、蒸気仕掛けが施された特殊なアクセサリーやペンダントを愛用している。",
  356. "【蒸気杖/傘】 あなたは、特殊機能を備えた蒸気機械式の傘を、あるいはステッキを愛用している。",
  357. "【ゴーグル】 あなたは、特殊機能を備えたゴーグルを愛用している。",
  358. "【特殊眼鏡】 あなたは、拡大機能などを備えた眼鏡や単眼鏡を愛用している。",
  359. "【蒸気ライター】 あなたは、小さなマグナイトが仕込まれた蒸気式ライターを隠し持っている。",
  360. "【機関手袋】 あなたは、特殊機能を備えた頑丈な革手袋を愛用している。",
  361. "【偽造カード】 あなたは、偽造した戸籍情報を点刻したパンチカードを隠し持っている。"
  362. ]
  363. ),
  364. "FPT" => SPTable.new(
  365. "特徴表P",
  366. [
  367. "【傷】 顔、あるいは体のどこかに傷がある。",
  368. "【美声】 一度聞くと忘れられないほど、美しい声だ。",
  369. "【筋肉質】 鍛え抜かれた肉体をしている。",
  370. "【美形】 生きている宝石のように美しい容貌をしている。",
  371. "【童顔】 年齢に関係なく、非常に若く見える。",
  372. "【髪】 不思議な髪の色、あるいはパンクな髪型をしている。",
  373. "【刺青】 体のどこかに特徴的なタトゥーがある。",
  374. "【瞳】 不思議な瞳の色、あるいは特徴的な眼差しをしている。"
  375. ]
  376. ),
  377. "RST" => SPTable.new(
  378. "関係性表S",
  379. [
  380. "【元敵同士】 相手とは、元敵同士の間柄だ。どのように敵対していたかは、プレイヤーと相談して決定せよ。",
  381. "【愛憎】 相手とは、愛憎渦巻く仲だ。愛しあっていた、憎みあっていたのかはプレイヤーと相談して決定せよ。",
  382. "【元相棒】 相手とは、元相棒の間柄だ。なぜ相棒でなくなったかについてはプレイヤーと相談して決定せよ。",
  383. "【犬猿】 相手とは、犬猿の仲だ。なぜ、いがみあっているかについてはプレイヤーと相談して決定せよ。",
  384. "【共依存】 相手とは、共依存の関係だ。どのように依存しあっているかはプレイヤーと相談して決定せよ。",
  385. "【仇同士】 相手とは、仇同士の間柄だ。どのような因縁であるかはプレイヤーと相談して決定せよ。",
  386. "【主従】 相手とは、主従の間柄だ。どちらが主で、どちらが従者かはプレイヤーと相談して決定せよ。",
  387. "【裏切り】 相手とは、裏切りあった間柄だ。どちらが裏切ったかについてはプレイヤーと相談して決定せよ。"
  388. ]
  389. ),
  390. "RPT" => SPTable.new(
  391. "関係性表P",
  392. [
  393. "【血縁】 相手とは、血縁がある。どの程度の間柄であるかについてはプレイヤーと相談して決定せよ。",
  394. "【同志】 相手は、同じ志を持っている。どんな志を共にしているかはプレイヤーと相談して決定せよ。",
  395. "【好敵手】 相手とは、良きライバルだ。どのような形での好敵手かは、プレイヤーと相談して決定せよ。",
  396. "【親友】 相手とは、親友の間柄だ。どのくらい仲が良いかについては、プレイヤーと相談して決定せよ。",
  397. "【相棒】 相手は、無二の相棒だ。どのくらいの年月を共にしてきたかについてはプレイヤーと相談して決定せよ。",
  398. "【腐れ縁】 相手とは幼い頃からの腐れ縁だ。どのくらいの年齢からであるかはプレイヤーと相談して決定せよ。",
  399. "【戦友】 相手とは戦友の間柄だ。どこで、なにと戦ったかについてはプレイヤーと相談して決定せよ。",
  400. "【師弟】 相手は師、あるいは弟子だ。どちらが師で、どちらが弟子かはプレイヤーと相談して決定せよ。"
  401. ]
  402. ),
  403. "EST" => SPTable.new(
  404. "感情表S",
  405. [
  406. "【殺意】 相手に殺意を覚えている。どういった経緯で殺意を抱いているかについては自身で決定せよ。",
  407. "【優越感】 相手に優越感がある。どういった経緯で優越感を抱いているかについては自身で決定せよ。",
  408. "【嫉妬】 相手に嫉妬している。どういった経緯で嫉妬しているかについては自身で決定せよ。",
  409. "【劣等感】 相手に劣等感がある。どういった経緯で劣等感を抱いているかについては自身で決定せよ。",
  410. "【罪悪感】 相手に罪悪感がある。どういった経緯で罪悪感を持っているかについては自身で決定せよ。",
  411. "【不安】 相手のことが不安だ。どういったときに不安を感じるかについては自身で決定せよ。",
  412. "【恐怖】 相手のことを恐れている。どういった経緯で恐れるようになったかについては自身で決定せよ。",
  413. "【嫌悪】 相手のことを嫌悪している。どの程度の嫌悪であるかについては自身で決定せよ。"
  414. ]
  415. ),
  416. "EPT" => SPTable.new(
  417. "感情表P",
  418. [
  419. "【誠意】 相手に対して誠意を感じる。どういった経緯で誠意を感じたかについては自身で決定せよ。",
  420. "【好感】 相手に対して好感を抱いている。どういった経緯で好感を抱くに至ったかについては自身で決定せよ。",
  421. "【尊敬】 相手のことを尊敬している。どういった経緯で相手を尊敬したかについては自身で決定せよ。",
  422. "【友情】 相手に対して友情を抱いている。どういった経緯で友情を抱くに至ったかについては自身で決定せよ。",
  423. "【庇護】 相手を護りたいと思っている。どういった経緯で相手を庇護対象にしたかは自身で決定せよ。",
  424. "【信頼】 相手のことを信頼している。どういった経緯で信頼するようになったかについては自身で決定せよ。",
  425. "【期待】 相手に対して期待している。どういった経緯で期待を抱くようになったかについては自身で決定せよ。",
  426. "【愛情】 相手に愛情や友愛を抱いている。どういった経緯で愛情を抱くに至ったかについては自身で決定せよ。"
  427. ]
  428. ),
  429. "ODT" => SPTable.new(
  430. "災厄表",
  431. [
  432. "【蒸気の不調】 スチームギアが不調になった!おそらくマグナイトが尽きかけてるのだ。ペナルティーを受けたPCは、そのフェイズの終了まで、スチームの抑圧を解放できない。",
  433. "【卑劣な強襲】 突如として強力な不意討ちを受けた。おそらく、スチームギアによる特殊な攻撃だ。PC全員は【耐久値】を-3する(最小1)。",
  434. "【非道な行為】 黒幕は気まぐれから、罪のない人をスチームギアで傷つけた。なんという非道な行為だ!PC全員は世界からの抑圧を2枚受ける。",
  435. "【嫌な予感】 今回の蒸気事件は特に嫌な予感がする……以後、全てのエネミーは終了フェイズを迎えるまで、実行の《アビリティ》の成功数を+1する。",
  436. "【敵役出現】 見知らぬ妨害者が現れた!以後、[【反抗LV】の平均以下]のエネミーが、そのフェイズに1人参加。戦闘不能にしない限り、メインを迎える度に実行を行ない、活劇フェイズにも参加する。",
  437. "【迎撃準備】 黒幕は万が一に備えて、手下を武装させ始めた。以後、全てのエネミーはシナリオ中、【耐久値】を+3する。",
  438. "【疑惑の目】 まずい。警察や政府がキミたちに対して疑惑の目を向け始めているようだ。PC全員は【理性値】を-2する(最小0)。",
  439. "【絶望感】 突如として心の傷が痛み、信念が揺らいでしまう。ペナルティーを受けたPCは、そのフェイズの終了まで、パンクの抑圧を解放できない。"
  440. ]
  441. ),
  442. "OST" => SPTable.new(
  443. "場面表",
  444. [
  445. "【地下鉄】 途中まで、地下鉄を利用することにする。駅のホームは蒸気列車が放出する蒸気のせいで、湿り気と熱気を帯びていた。",
  446. "【工業地帯】 工業地帯を横切る。開かれた窓の奥に視線を送ると、労働者たちが製造用蒸気機関を操り、真鍮製の煙突から蒸気が噴き上っている。",
  447. "【店舗】 途中、店舗で簡単な買い物を済ませた。支払いは無論、パンチカードで一括。階差演算機関はすでに個人の予算残高すら管理下に置いている。",
  448. "【ビッグ・ベン】 遠くから時刻を告げるビッグ・ベンの鐘が響くと、蒸気オルガンの薄暗い音色が、いつものようにロンドンの上空を覆った。",
  449. "【人混み】 人混みのなかを進むと、ハンチング帽をかぶった少年たちが脇を駆け抜けた……彼らを護るためにも早く蒸気事件を解決しなければ。",
  450. "【繁華街】 調査に向かった現場では、蒸気機械仕掛けの帯状装飾が点灯しており、帯が回転する度に様々な広告が表示された。",
  451. "【大通り】 大通りに出ると、蒸気自動車が目前で行き交っていた。真鍮や錫で装飾された蒸気自動車は、まるで晩餐会に出入りする馬車のようだ。",
  452. "【移動パブ】 途中、移動パブを見かけた。蒸気自動車に機関式サーバーを搭載したもので、周りには若いロンドン子たちが口に泡をつけながら騒いでいる。"
  453. ]
  454. ),
  455. "OIT" => SPTable.new(
  456. "交流表",
  457. [
  458. "【過去】 そういえば、相手の過去を知らない気がする…聞けば教えてくれるだろうか?",
  459. "【特徴】 さっきから相手の特徴が気になる。相手から特徴にまつわる話を聞いてみようか?",
  460. "【感情】 相手に対して抱いてる感情のことを伝えるべきだろうか?それとも、伝えないべきだろうか?",
  461. "【蒸気事件】 相手に、今回の事件の印象について聞いてみよう。",
  462. "【事件後】 今回の事件が終わったら、相手は何をするつもりなのだろう?",
  463. "【関係性】 相手とは……いつからこうした関係だったろう?そもそも、相手は覚えているのだろうか?",
  464. "【職業】 相手は、どんな経緯で今の職業となったのだろう。興味があるので、聞いてみようか?",
  465. "【経緯】 相手はどうやってスチームギアを得たのだろう?その経緯の一部でも聞いてみようか?"
  466. ]
  467. ),
  468. "OFT" => SPTable.new(
  469. "激憤表",
  470. [
  471. "【憤怒】 これほど残虐な蒸気事件が起こったというのに、世界は一向に変わろうとしない。もはや世界への怒りは頂点へと達してしまった。PCはレヴォルトを失い、黒幕となる。",
  472. "【破損】 怒りに任せて激闘を繰り返したため、スチームギアが破損した。もう、世界に反逆する力はない。以後、PCはスチームギアを失い、NPCとなる。",
  473. "【偽装】 権力者からの圧力によって、社会的に抹殺されてしまった。が、それは想定済みだ。これからは別の人生を歩むことになる。PCの名前と職業を変更せよ。",
  474. "【冷静】 今回の蒸気事件には少し思うところがあった。だが、しばらく時間を置くことで、理性的になることができた。キミはまだまだ戦える。特にペナルティーはない。",
  475. "【重傷】 最後の戦いの際に負った傷が重症化してしまった。だが、しばらく治療に専念すれば復帰できるだろう。特にペナルティーはない。",
  476. "【革命】 今回の事件を通じて、信念が揺らいだ。やはり、世界を変えるには圧倒的な”暴力”が必要なのだ。PCはレヴォルトを失い、黒幕となる。",
  477. "【寝返り】 蒸気事件を通じて、世界の在り方に疑問を感じる。そんな矢先、目前にゾディアックの上級幹部が現れ、キミをスカウトしてきた。PCはレヴォルトを失い、黒幕となる。",
  478. "【悪堕ち】 信念に従い、反逆を続けてきた。だが、蒸気事件が尽きる気配はない。反逆など無意味なのか。なら、この手で……PCはレヴォルトを失い、黒幕となる。"
  479. ]
  480. )
  481. }.freeze
  482. 1 register_prefix('SP', TABLES.keys)
  483. end
  484. end
  485. end

lib/bcdice/game_system/StellarKnights.rb

98.86% lines covered

93.33% branches covered

88 relevant lines. 87 lines covered and 1 lines missed.
30 total branches, 28 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/dice_table/table"
  3. 1 require "bcdice/dice_table/d66_grid_table"
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class StellarKnights < Base
  7. # ゲームシステムの識別子
  8. 1 ID = 'StellarKnights'
  9. # ゲームシステム名
  10. 1 NAME = '銀剣のステラナイツ'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = 'きんけんのすてらないつ'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = <<~MESSAGETEXT
  15. ・アタック判定 nSK[d][,k>l,...]
  16. []内は省略可能。
  17. n: ダイス数、d: アタック判定における対象の防御力、k, l: ダイスの出目がkならばlに変更(アマランサスのスキル「始まりの部屋」用)
  18. d省略時はダイスを振った結果のみ表示。(nSKはnB6と同じ)
  19. 4SK: ダイスを4個振って、その結果を表示
  20. 4+2SK: ダイスを4+2 (=6) 個振って、その結果を表示
  21. 5/2SK: ダイスを5個の半分 (=2) 個振って、その結果を表示
  22. (5+3)/2SK: ダイスを(5+3)個の半分 (=4) 個振って、その結果を表示
  23. 5SK3: 【アタック判定:5ダイス】、対象の防御力を3として成功数を表示
  24. 3SK,1>6: ダイスを3個振り、出目が1のダイスを全て6に変更し、その結果を表示
  25. 6SK4,1>6,2>6: 【アタック判定:6ダイス】、出目が1と2のダイスを全て6に変更、対象の防御力を4として成功数を表示
  26. ・基本
  27. TT:お題表
  28. STA :シチュエーション表A:時間 (Situation Table A)
  29. STB :シチュエーション表B:場所 (ST B)
  30. STB2[n]:シチュエーション表B その2:学園編 (ST B 2)
  31.  n: 1(アーセルトレイ), 2(イデアグロリア), 3(シトラ), 4(フィロソフィア), 5(聖アージェティア), 6(SoA)
  32. STC :シチュエーション表C:話題 (ST C)
  33. ALLS :シチュエーション表全てを一括で(学園編除く)
  34. GAT:所属組織決定 (Gakuen Table)
  35. HOT:希望表 (Hope Table)
  36. DET:絶望表 (Despair Table)
  37. WIT:願い事表 (Wish Table)
  38. YST:あなたの物語表 (Your Story Table)
  39. YSTA:あなたの物語表:異世界 (YST Another World)
  40. PET:性格表 (Personality Table)
  41. 性格表を2回振り、性格を決定する
  42. ・霧と桜のマルジナリア
  43. YSTM:あなたの物語表:マルジナリア世界 (YST Marginalia)
  44. STM:シチュエーション表:マルジナリア世界 (ST Marginalia)
  45. YSTL:あなたの物語表:手紙世界 (YST Letter)
  46. YSTR:あなたの物語表:リコレクト・ドール (YST Recollect-doll)
  47. STBR:シチュエーション表B:場所(リコレクト・ドール) (ST B Recollect-doll)
  48. STCR:シチュエーション表C:リコレクト (ST C Recollect)
  49. STBS:シチュエーション表B:シトラセッティング (ST B Sut Tu Real)
  50. STE:シチュエーション表:エクリプス専用 (ST Eclipse)
  51. ・紫弾のオルトリヴート
  52. FT:フラグメント表 (Fragment Table)
  53. フラグメント表を5回振る
  54. FTx:フラグメント表をx回振る
  55. YSTB:あなたの物語表:ブリンガー (YST Bringer)
  56. YSTF:あなたの物語表:フォージ (YST Forge)
  57. STAL:シチュエーション表:オルトリヴート (ST Alt-Levoot)
  58. MESSAGETEXT
  59. 1 def initialize(command)
  60. 213 super(command)
  61. 213 @sort_barabara_dice = true # バラバラロール(Bコマンド)でソート有
  62. 213 @d66_sort_type = D66SortType::NO_SORT
  63. end
  64. 1 def eval_game_system_specific_command(command)
  65. 211 command = command.upcase
  66. 211 then: 158 if (table = self.class::TABLES[command])
  67. 158 else: 53 table.roll(@randomizer)
  68. 53 then: 31 elsif (m = %r{([()+/\d]+)SK(\d)?((,\d>\d)+)?}.match(command))
  69. 31 num_dices = Arithmetic.eval(m[1], RoundType::FLOOR)
  70. 31 else: 2 then: 29 unless num_dices.nil?
  71. 29 resolute_action(num_dices, m[2] && m[2].to_i, m[3])
  72. else: 22 end
  73. 22 then: 2 elsif command == 'STB2'
  74. 2 else: 20 roll_all_situation_b2_tables
  75. 20 then: 2 elsif command == 'ALLS'
  76. 2 else: 18 roll_all_situation_tables
  77. 18 then: 6 elsif command == "PET"
  78. 6 else: 12 roll_personality_table
  79. 12 then: 12 else: 0 elsif (m = /FT(\d+)?/.match(command))
  80. 12 num = (m[1] || 5).to_i
  81. 12 roll_fragment_table(num)
  82. end
  83. end
  84. 1 private
  85. # @param [Integer] num_dices
  86. # @param [Integer | nil] defence
  87. # @param [String] dice_change_text
  88. # @return [Result, String]
  89. 1 def resolute_action(num_dices, defence, dice_change_text)
  90. 29 dices = @randomizer.roll_barabara(num_dices, 6).sort
  91. 29 dice_text = dices.join(",")
  92. 29 output = "(#{remake_command(num_dices, defence, dice_change_text)}) > #{dice_text}"
  93. 29 then: 6 else: 23 if dices.empty?
  94. 6 return output + translate("StellarKnights.SK.no_dice_error")
  95. end
  96. # FAQによると、ダイスの置き換えは宣言された順番に適用されていく
  97. 23 dice_change_rules = parse_dice_change_rules(dice_change_text)
  98. 23 dice_change_rules.each do |rule|
  99. 68 then: 12 else: 45 dices.map! { |val| val == rule[:from] ? rule[:to] : val }
  100. end
  101. 23 else: 16 then: 7 unless dice_change_rules.empty?
  102. 7 dices.sort!
  103. 7 output += " > [#{dices.join(',')}]"
  104. end
  105. 23 then: 15 if defence.nil?
  106. 15 success = false
  107. 15 failure = false
  108. else: 8 else
  109. 48 success_num = dices.count { |val| val >= defence }
  110. 8 output += " > " + translate("StellarKnights.SK.success_num", success_num: success_num)
  111. 8 success = success_num > 0
  112. 8 failure = !success
  113. end
  114. 23 Result.new(output).tap do |r|
  115. 23 r.success = success
  116. 23 r.failure = failure
  117. end
  118. end
  119. 1 def remake_command(num_dices, defence, dice_change_text)
  120. 29 command = "#{num_dices}SK"
  121. 29 else: 18 then: 11 command += defence.to_s unless defence.nil?
  122. 29 else: 20 then: 9 command += dice_change_text unless dice_change_text.nil?
  123. 29 command
  124. end
  125. 1 def parse_dice_change_rules(text)
  126. 23 then: 16 else: 7 return [] if text.nil?
  127. # 正規表現の都合で先頭に ',' が残っているので取っておく
  128. 7 text = text[1..-1]
  129. 7 text.split(',').map do |rule|
  130. 11 v = rule.split('>').map(&:to_i)
  131. {
  132. 11 from: v[0],
  133. to: v[1],
  134. }
  135. end
  136. end
  137. 1 def roll_all_situation_b2_tables
  138. 14 (1..6).map { |num| self.class::TABLES["STB2#{num}"].roll(@randomizer) }.join("\n")
  139. end
  140. 1 def roll_all_situation_tables
  141. 8 ['STA', 'STB', 'STC'].map { |command| self.class::TABLES[command].roll(@randomizer) }.join("\n")
  142. end
  143. 1 def roll_personality_table
  144. 6 value1, index1 = get_table_by_d66(translate("StellarKnights.PET.items"))
  145. 6 value2, index2 = get_table_by_d66(translate("StellarKnights.PET.items"))
  146. 6 name = translate("StellarKnights.PET.name")
  147. 6 result = translate("StellarKnights.PET.result", value1: value1, value2: value2)
  148. 6 return "#{name}(#{index1},#{index2}) > #{result}"
  149. end
  150. 1 def roll_fragment_table(num)
  151. 12 then: 0 else: 12 if num <= 0
  152. return nil
  153. end
  154. 60 results = Array.new(num) { get_table_by_d66(translate("StellarKnights.FT.items")) }
  155. 60 values = results.map { |r| r[0] }
  156. 60 indexes = results.map { |r| r[1] }
  157. 12 name = translate("StellarKnights.FT.name")
  158. 12 return "#{name}(#{indexes.join(',')}) > #{values.join(translate('StellarKnights.FT.sep'))}"
  159. end
  160. 1 class << self
  161. 1 private
  162. 1 def translate_tables(locale)
  163. {
  164. 2 "TT" => DiceTable::D66GridTable.from_i18n("StellarKnights.tables.TT", locale),
  165. "STA" => DiceTable::Table.from_i18n("StellarKnights.tables.STA", locale),
  166. "STB" => DiceTable::D66OneThirdTable.from_i18n("StellarKnights.tables.STB", locale),
  167. "STB21" => DiceTable::Table.from_i18n("StellarKnights.tables.STB21", locale),
  168. "STB22" => DiceTable::Table.from_i18n("StellarKnights.tables.STB22", locale),
  169. "STB23" => DiceTable::Table.from_i18n("StellarKnights.tables.STB23", locale),
  170. "STB24" => DiceTable::Table.from_i18n("StellarKnights.tables.STB24", locale),
  171. "STB25" => DiceTable::Table.from_i18n("StellarKnights.tables.STB25", locale),
  172. "STB26" => DiceTable::Table.from_i18n("StellarKnights.tables.STB26", locale),
  173. "STC" => DiceTable::D66HalfGridTable.from_i18n("StellarKnights.tables.STC", locale),
  174. "GAT" => DiceTable::Table.from_i18n("StellarKnights.tables.GAT", locale),
  175. "HOT" => DiceTable::D66HalfGridTable.from_i18n("StellarKnights.tables.HOT", locale),
  176. "DET" => DiceTable::D66HalfGridTable.from_i18n("StellarKnights.tables.DET", locale),
  177. "WIT" => DiceTable::D66OneThirdTable.from_i18n("StellarKnights.tables.WIT", locale),
  178. "YST" => DiceTable::D66OneThirdTable.from_i18n("StellarKnights.tables.YST", locale),
  179. "YSTA" => DiceTable::D66OneThirdTable.from_i18n("StellarKnights.tables.YSTA", locale),
  180. "YSTM" => DiceTable::D66OneThirdTable.from_i18n("StellarKnights.tables.YSTM", locale),
  181. "STM" => DiceTable::D66HalfGridTable.from_i18n("StellarKnights.tables.STM", locale),
  182. "YSTL" => DiceTable::D66HalfGridTable.from_i18n("StellarKnights.tables.YSTL", locale),
  183. "YSTR" => DiceTable::D66HalfGridTable.from_i18n("StellarKnights.tables.YSTR", locale),
  184. "STBR" => DiceTable::D66HalfGridTable.from_i18n("StellarKnights.tables.STBR", locale),
  185. "STCR" => DiceTable::D66HalfGridTable.from_i18n("StellarKnights.tables.STCR", locale),
  186. "STBS" => DiceTable::D66HalfGridTable.from_i18n("StellarKnights.tables.STBS", locale),
  187. "STE" => DiceTable::D66HalfGridTable.from_i18n("StellarKnights.tables.STE", locale),
  188. "YSTB" => DiceTable::D66HalfGridTable.from_i18n("StellarKnights.tables.YSTB", locale),
  189. "YSTF" => DiceTable::D66HalfGridTable.from_i18n("StellarKnights.tables.YSTF", locale),
  190. "STAL" => DiceTable::D66HalfGridTable.from_i18n("StellarKnights.tables.STAL", locale),
  191. }
  192. end
  193. end
  194. 1 TABLES = translate_tables(:ja_jp)
  195. 1 register_prefix('[()+\/\d]+SK', 'STB2', 'ALLS', 'PET', 'FT', TABLES.keys)
  196. end
  197. end
  198. end

lib/bcdice/game_system/StellarKnights_Korean.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/StellarKnights"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class StellarKnights_Korean < StellarKnights
  6. # ゲームシステムの識別子
  7. 1 ID = "StellarKnights:Korean"
  8. # ゲームシステム名
  9. 1 NAME = "은검의 스텔라나이츠"
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = "国際化:Korean:은검의 스텔라나이츠"
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・판정 nSK[d][,k>l,...]
  15. []안은 생략 가능.
  16. n: 다이스 개수, d: 공격 판정 대상의 방어력, k>l: 다이스를 굴려 k가 나오면 l로 변경(아마란서스 스킬 중「시작의 방」용)
  17. d 생략 시 다이스를 굴린 결과만 표시. (nSK는 nB6과 동일)
  18. 4SK: 다이스 4개를 굴린 결과 표시.
  19. 4+2SK: ダイスを4+2 (=6) 個振って、その結果を表示
  20. 5/2SK: ダイスを5個の半分 (=2) 個振って、その結果を表示
  21. (5+3)/2SK: ダイスを(5+3)個の半分 (=4) 個振って、その結果を表示
  22. 5SK3: 【공격 판정: 5다이스】, 대상의 방어력을 3으로 계산해 성공 수 표시.
  23. 3SK,1>6: 다이스 3개 굴림, 1이 나오면 전부 6으로 변경, 대상의 방어력을 4로 계산해 성공 수 표시.
  24. 6SK4,1>6,2>6: 【공격 판정: 6다이스】, 1과 2가 나오면 전부 6으로 변경, 대상의 방어력을 4로 계산해 성공 수 표시.
  25. ・기본
  26. TT: 소재 표
  27. STA: 상황 표 A: 시간 (Situation Table A)
  28. STB: 상황 표 B-1: 장소 (ST B)
  29. STB2[n]: 상황 표 B-2: 학원편 (ST B 2)
  30.  n: 1(아셀트레이 공립대학), 2(이데아글로리아 예술종합대학), 3(시트라 여학원), 4(필로소피아 대학), 5(성 아제티아 학원), 6(스폰 오브 아셀트레이)
  31. STC: 상황 표 C: 화제 (ST C)
  32. ALLS: 상황 표 전체 일괄 굴림 (학원편 제외)
  33. GAT: 소속 조직 결정 (Gakuen Table)
  34. HOT: 희망 표 (Hope Table)
  35. DET: 절망 표 (Despair Table)
  36. WIT: 소원 표 (Wish Table)
  37. YST: 당신의 이야기 표 (Your Story Table)
  38. YSTA: 당신의 이야기 표 (이세계) (YST Another World)
  39. PET: 성격 표 (Personality Table)
  40. 성격 표를 2번 굴려 성격을 결정한다.
  41. ・안개와 벚꽃의 마르지날리아
  42. YSTM: 당신의 이야기 표 (마르지날리아) (YST Marginalia)
  43. STM: 상황 표: 마르지날리아 (ST Marginalia)
  44. YSTL: 당신의 이야기 표 (편지) (YST Letter)
  45. YSTR: 당신의 이야기 표 (리콜렉트 돌) (YST Recollect-doll)
  46. STBR: 상황 표 B: 장소 (리콜렉트 돌) (ST B Recollect-doll)
  47. STCR: 상황 표 C: 리콜렉트 (ST C Recollect)
  48. STBS: 상황 표 B: 시트라 세팅 (ST B Sut Tu Real)
  49. STE: 상황 표: 이클립스 전용 (ST Eclipse)
  50. ・자탄의 알트리부트
  51. FT: 프래그먼트 표 (Fragment Table)
  52. 프래그먼트 표를 5번 굴린다.
  53. FTx: 프래그먼트 표를 x회 굴린다.
  54. YSTB: 당신의 이야기 (브링거) (YST Bringer)
  55. YSTF: 당신의 이야기 (포지) (YST Forge)
  56. STAL: 상황 표 (알트리부트) (ST Alt-Levoot)
  57. INFO_MESSAGE_TEXT
  58. 1 register_prefix_from_super_class()
  59. 1 def initialize(command)
  60. 104 super(command)
  61. 104 @locale = :ko_kr
  62. end
  63. 1 TABLES = translate_tables(:ko_kr).freeze
  64. end
  65. end
  66. end

lib/bcdice/game_system/StellarLife.rb

100.0% lines covered

96.67% branches covered

80 relevant lines. 80 lines covered and 0 lines missed.
30 total branches, 29 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class StellarLife < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'StellarLife'
  7. # ゲームシステム名
  8. 1 NAME = 'ステラーライフTRPG'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'すてらあらいふTRPG'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ◆判定 nDAc[s,d,t] n:ダイス数 c:各種修正 s:1成功(省略不可) d:2成功(省略不可) t:3成功(ダイス目一致時のみ 省略時:無し)
  14.  例)2DA-3[7,10]
  15. ◆船名ランダム表
  16.  ・船名接頭辞表 VPFT
  17.  ・船名前半表 VNFT
  18.  ・船名後半表 VNRT
  19.  ・アバターアルファベット表① AAFT
  20.  ・アバターアルファベット表② AAST
  21. ◆ヴォヤージュ各種表
  22.  ・ランダムNPC艦表 RNST
  23.  ・ランダムイベント表 RET
  24.  ・お宝特徴表 TRST
  25.  ・お宝形容表 TRAT
  26.  ・お宝外見表 TRMT
  27.  ・お宝物品表 TROT
  28. ◆ステラーライフお題表
  29.  ・超未来の技術 TET
  30.  ・超未来のエンタメ ENT
  31.  ・超未来の文化 CUT
  32.  ・超未来の自然 NAT
  33.  ・超未来の宇宙船内 INT
  34. MESSAGETEXT
  35. 1 register_prefix('\d*DA')
  36. 1 def eval_game_system_specific_command(command)
  37. # 通常判定部分をgetJudgeResultコマンドに切り分け
  38. 97 output = getJudgeResult(command)
  39. 97 else: 90 then: 7 return output unless output.nil?
  40. # テーブル
  41. 90 table = TABLES[command]
  42. 90 else: 1 then: 89 return table.roll(@randomizer) unless table.nil?
  43. 1 nil
  44. end
  45. 1 def getJudgeResult(command)
  46. 97 case command
  47. when: 7 when /(\d+)?DA([\d+*-]*\d)?\[(\d+),(\d+)(,(\d+))?\]/i
  48. 7 number = (Regexp.last_match(1) || 1).to_i
  49. 7 correction = (Regexp.last_match(2) || 0).to_i
  50. 7 single = (Regexp.last_match(3) || 4).to_i
  51. 7 double = (Regexp.last_match(4) || 8).to_i
  52. 7 triple = (Regexp.last_match(6) || -1).to_i
  53. else: 90 else
  54. 90 return nil
  55. end # ^は行頭 $は行末 iは大文字小文字区別しない https://ruby-doc.org/core-2.7.0/Regexp.html
  56. 7 success = 0
  57. 7 dicetext = ""
  58. 7 corrected = ""
  59. 7 then: 0 else: 7 if number <= 0 then number = 1 end
  60. 7 number.times do
  61. 32 dice = @randomizer.roll_once(10)
  62. 32 then: 8 else: 24 dice = 0 if dice == 10
  63. 32 then: 14 else: 18 if (dice + correction) >= single || dice == triple then success += 1 end
  64. 32 then: 5 else: 27 if (dice + correction) >= double || dice == triple then success += 1 end
  65. 32 then: 1 else: 31 if dice == triple then success += 1 end # unless triple == -1 3成功はダイス目一致時のみ
  66. 32 then: 7 if dicetext == ""
  67. 7 dicetext = dice.to_s
  68. 7 corrected = (dice + correction).to_s
  69. else: 25 else
  70. 25 dicetext = dicetext + "," + dice.to_s
  71. 25 corrected = corrected + "," + (dice + correction).to_s
  72. end
  73. end
  74. 7 then: 5 else: 2 if correction == 0
  75. 5 result = "(#{dicetext}) > 成功数#{success}"
  76. end
  77. 7 then: 1 else: 6 if correction > 0
  78. 1 result = "(#{dicetext}) +#{correction} > (#{corrected}) > 成功数#{success}"
  79. end
  80. 7 then: 1 else: 6 if correction < 0
  81. 1 result = "(#{dicetext}) #{correction} > (#{corrected}) > 成功数#{success}"
  82. end
  83. 7 return result
  84. end
  85. 1 class StellarLifeD10Table < DiceTable::Table
  86. 1 def initialize(name, items)
  87. 8 super(name, '1D10', items)
  88. end
  89. 1 def choice(value)
  90. 29 index = value - @times
  91. 29 return RollResult.new(@name, value, @items[index])
  92. end
  93. # このゲームでは D10 の出目 10 を 0 と読む
  94. 1 class RollResult < DiceTable::RollResult
  95. 1 def to_s
  96. 29 then: 8 else: 21 "#{@table_name}(#{@value == 10 ? 0 : value}) > #{@body}"
  97. end
  98. end
  99. end
  100. # 紙面上で 0 始まり 9 終わりの D10 テーブル( 0, 1, 2, ..., 8, 9 )
  101. 1 class StellarLifeD10_0to9_Table < StellarLifeD10Table
  102. 1 def initialize(name, *items)
  103. 3 super(name, items[1..9] + [items[0]]) # 出目 10 を 0 と読む(表示する)ため、 0 番目を末尾に回す.
  104. end
  105. end
  106. # 紙面上で 1 始まり 0 終わりの D10 テーブル( 1, 2, 3, ..., 8, 9, 0 )
  107. 1 class StellarLifeD10_1to0_Table < StellarLifeD10Table
  108. 1 def initialize(name, *items)
  109. 5 super(name, items)
  110. end
  111. end
  112. # D10 を 2 個振って、 100 通りの結果を得るテーブル
  113. # (このゲームではこの振り方の表に 2D10 と書いてあるので、そういう名前にしてある)
  114. 1 class StellarLife2D10Table
  115. 1 def initialize(name, *items)
  116. 8 @name = name
  117. 8 @items = items.freeze
  118. end
  119. 1 def roll(randomizer)
  120. 60 dices = randomizer.roll_barabara(2, 10)
  121. 60 then: 16 else: 44 row_index = dices[0] == 10 ? 0 : dices[0]
  122. 60 then: 13 else: 47 column_index = dices[1] == 10 ? 0 : dices[1]
  123. 60 key = row_index * 10 + column_index
  124. 60 chosen = @items[key]
  125. 60 return RollResult.new(@name, format("%02d", key), chosen)
  126. end
  127. # 出目 10 を 0 と読むため、ゼロパディングしなければならない
  128. 1 class RollResult < DiceTable::RollResult
  129. 1 def to_s
  130. 60 "#{@table_name}(#{format('%02d', @value)}) > #{@body}"
  131. end
  132. end
  133. end
  134. # D10 を 2 個振って、 50 通りの結果を得るテーブル
  135. #
  136. # イメージ図:
  137. #
  138. # [0-1] [2-3] .. [8-9]
  139. # [0]
  140. # [1]
  141. # [2]
  142. # :
  143. # [8]
  144. # [9]
  145. #
  146. # (c.f. ルールブック p120, p123 )
  147. 1 class StellarLife2D10HalfTable < StellarLife2D10Table
  148. 1 def initialize(name, items)
  149. 2 super(
  150. name,
  151. *items.map do |row|
  152. 20 row.map do |value|
  153. 100 [value, value]
  154. end.flatten
  155. end.flatten
  156. )
  157. end
  158. end
  159. TABLES = {
  160. 1 'VPFT' => StellarLifeD10_0to9_Table.new(
  161. '船名接頭辞表',
  162. 'ISS(独立宇宙船)',
  163. 'PCS(惑星運搬船)',
  164. 'NSS(中立星間船)',
  165. 'SMS(星間商船)',
  166. 'PSS(民間宇宙船)',
  167. 'CIS(勅許独立船)',
  168. 'FTS(自由貿易船)',
  169. 'OES(外縁探検船)',
  170. 'SSS(主権星間船)',
  171. 'HMS(陛下の船)'
  172. ),
  173. 'VNFT' => StellarLife2D10Table.new(
  174. '船名前半表',
  175. 'ブラック', 'ホワイト', 'レッド', 'ブルー', 'グリーン', 'パープル', 'ライラック', 'ブラウン', 'シルバー', 'ゴールド',
  176. 'ネイビー', 'マリン', 'オーシャン', 'アクア', 'セイル', 'アンカー', 'パイレーツ', 'プライヴァティア', 'アルマダ', 'フロティラ',
  177. 'ギャリソン', 'タンク', 'センチネル', 'スクァッド', 'トループ', 'フロント', 'オフェンシブ', 'ヴァンガード', 'オーダー', 'フラッグ',
  178. 'ゲイザー', 'アストロ', 'ステラー', 'ギャラクティック', 'スターリー', 'ミルキー', 'プラネタリー', 'ゾディアック', 'ポラリス', 'イクェータ',
  179. 'アイアンクラッド', 'サイエンス', 'ストーン', 'ソリッド', 'ウッド', 'ストック', 'フロー', 'ブレイズ', 'ディヴァイン', 'グロリアス',
  180. 'ドラゴン', 'コヨーテ', 'ペガサス', 'カーバンクル', 'ガーゴイル', 'バジリスク', 'フェニックス', 'フェンリル', 'ケルベロス', 'キマイラ',
  181. 'ジュラフ', 'ディアー', 'ゼブラ', 'ホエール', 'ラクーン', 'キャメル', 'ペンギン', 'リザード', 'サーバル', 'エルク',
  182. 'フリー', 'ライト', 'リベラル', 'リッチ', 'エコノミー', 'マーケット', 'ナショナル', 'ソーシャル', 'エコロジカル', 'ナチュラル',
  183. 'ロイヤル', 'プリンシパル', 'インペリアル', 'マジェスティック', 'ノーブル', 'ロード', 'ハイネス', 'デューク', 'カウント', 'バロン',
  184. 'スモーク', 'クリア', 'ブリザード', 'ゲイル', 'ミスト', 'ヘイル', 'スノウ', 'ライトニング', 'サンダー', '(PC1人の名前)'
  185. ),
  186. 'VNRT' => StellarLife2D10Table.new(
  187. '船名後半表',
  188. 'ローズ', 'ダンデリオン', 'オーキッド', 'アザリア', 'スウォードリリー', 'アイリス', 'ラベンダー', 'プロテア', 'グラジオラス', 'マグノリア',
  189. 'ライナー', 'カッター', 'フライター', 'フェリー', 'バルジ', 'クルーザー', 'クラフト', 'リガー', 'キール', 'ヴェッセル',
  190. 'リミテッド', 'インク', 'マーチャント', 'エクスペディション', 'コンボイ', 'キャラバン', 'コマース', 'レティニュー', 'アドバイザリー', 'コンサルティング',
  191. 'テレスコープ', 'オブザーバー', 'グラス', 'コスモス', 'ヘブン', 'ノート', 'ロット', 'スペース', 'フェアラー', 'ノマド',
  192. 'ブローカー', 'ディーラー', 'ダイバー', 'ドライバー', 'アドベンチャラー', 'ランナー', 'ウォーカー', 'トラベラー', 'トレーダー', 'エクスプローラー',
  193. 'キャット', 'パンサー', 'ライオン', 'ピューマ', 'レオパルド', 'タイガー', 'ジャガー', 'オセロット', 'リンクス', 'チーター',
  194. 'ウォルフ', 'カメレオン', 'クラブ', 'オスカー', 'シャーク', 'イーグル', 'コンドル', 'ドルフィン', 'サウルス', 'フィッシュ',
  195. 'コンキスタドール', 'フサリア', 'ナイト', 'コサック', 'ヘタイロイ', 'バーサーカー', 'レギオン', 'ウォリアー', 'テルシオ', 'ライダー',
  196. 'ルール', 'ディメイン', 'レイン', 'ジャスティス', 'エンクレーブ', 'ステート', 'カントリー', 'レルム', 'ドミニオン', 'ソブリン',
  197. 'ストーム', 'テンペスト', 'アヴァランチ', 'ストライク', 'フォール', 'クエイク', 'ハリケーン', 'ブラスター', 'ブリザード', '(PC1人の名前)'
  198. ),
  199. 'AAFT' => StellarLifeD10_0to9_Table.new(
  200. 'アバターアルファベット表①',
  201. 'A', 'F', 'G', 'I', 'J', 'K', 'R', 'S', 'T', 'V'
  202. ),
  203. 'AAST' => StellarLifeD10_0to9_Table.new(
  204. 'アバターアルファベット表②',
  205. 'D', 'F', 'L', 'M', 'N', 'O', 'R', 'S', 'X', 'Z'
  206. ),
  207. 'RNST' => StellarLife2D10HalfTable.new(
  208. 'ランダムNPC艦表',
  209. [
  210. ['装甲+20(HP+400)', '装甲+20(HP+400)', '〈電磁パルスフィールド〉1基', '〈中性粒子ビーム砲〉2基', '〈バリアフィールド〉2基'],
  211. ['装甲+20(HP+400)', '装甲+20(HP+400)', '〈電磁パルスフィールド〉1基', '〈高機動ミサイル〉2基', '〈バリアフィールド〉2基'],
  212. ['装甲+20(HP+400)', '装甲+20(HP+400)', '〈リサイクルフォージ〉', '〈高機動ミサイル〉2基', '〈バリアフィールド〉2基'],
  213. ['装甲+20(HP+400)', '装甲+20(HP+400)', '〈リサイクルフォージ〉', '〈高機動ミサイル〉2基', '〈レーザーディフェンス〉2基'],
  214. ['装甲+20(HP+400)', '〈ホーミング量子ビーム〉2基', '〈高圧縮精製装置〉', '〈アタックドローン〉1基', '〈レーザーディフェンス〉2基'],
  215. ['装甲+20(HP+400)', '〈ホーミング量子ビーム〉2基', '〈高圧縮精製装置〉', '〈爆縮高エネルギービーム砲〉2基', '〈レーザーディフェンス〉2基'],
  216. ['装甲+20(HP+400)', '〈ホーミング量子ビーム〉2基', '〈艦載メタルディテクター〉', '〈マグネティックアロイミサイル〉2基', '〈艦内防護装甲〉'],
  217. ['装甲+20(HP+400)', '〈ロングランスミサイル〉2基', '〈「スターブレイカー」のハリボテ〉', '〈ドローンアバター〉1基', '装甲+40(HP+800)'],
  218. ['装甲+20(HP+400)', '〈ロングランスミサイル〉2基', '〈中性粒子ビーム砲〉2基', '〈拡散粒子ビーム砲〉2基', '装甲+40(HP+800)'],
  219. ['装甲+20(HP+400)', '〈ロングランスミサイル〉2基', '〈中性粒子ビーム砲〉2基', '〈マイクロミサイルポッド〉2基', '装甲+40(HP+800)'],
  220. ]
  221. ),
  222. 'RET' => StellarLife2D10HalfTable.new(
  223. 'ランダムイベント表',
  224. [
  225. ['燃料1 《周辺探索》成功数0~1では推進剤[1D10×30]獲得', '鋼材1 《周辺探索》成功数0~1では鋼材[1D10×30]獲得', '金属塊 鋼材300を獲得', '砕けた惑星核 希少金属3を獲得', '大資源アステロイド 推進剤300、鋼材300を獲得'],
  226. ['燃料1 《周辺探索》成功数0~1では推進剤[1D10×30]獲得', '鋼材1 《周辺探索》成功数0~1では鋼材[1D10×30]獲得', 'S型アステロイド 鋼材400を獲得', '燃料1 《周辺探索》成功数0~1では推進剤[1D10×30]獲得', '氷火山アステロイド 推進剤300、希少金属1を獲得'],
  227. ['燃料1 《周辺探索》成功数0~1では推進剤[1D10×30]獲得', '巨大暗黒星雲 この星系ではビーム属性の攻撃の判定で達成値-1', 'S型アステロイド 鋼材400を獲得', '燃料1 《周辺探索》成功数0~1では推進剤[1D10×30]獲得', 'オーガニックアステロイド 推進剤700を獲得'],
  228. ['燃料1 《周辺探索》成功数0~1では推進剤[1D10×30]獲得', '超新星残骸 この星系では実体弾属性の攻撃の判定で達成値-1', 'スペースデブリ 鋼材500を獲得', '燃料1 《周辺探索》成功数0~1では推進剤[1D10×30]獲得', '金属塊 鋼材300を獲得'],
  229. ['燃料1 《周辺探索》成功数0~1では推進剤[1D10×30]獲得', 'C型アステロイド 推進剤400を獲得', 'スペースデブリ 鋼材500を獲得', '燃料1 《周辺探索》成功数0~1では推進剤[1D10×30]獲得', 'スペースデブリ 鋼材500を獲得'],
  230. ['鋼材1 《周辺探索》成功数0~1では鋼材[1D10×30]獲得', '氷のアステロイド群 推進剤500を獲得', 'M型アステロイド 鋼材600を獲得', '鋼材1 《周辺探索》成功数0~1では鋼材[1D10×30]獲得', 'M型アステロイド 鋼材600を獲得'],
  231. ['鋼材1 《周辺探索》成功数0~1では鋼材[1D10×30]獲得', '巨大アイスブロック 推進剤600を獲得', '艦船の残骸 鋼材700を獲得', '鋼材1 《周辺探索》成功数0~1では鋼材[1D10×30]獲得', '放棄されたモジュール 鋼材300、希少金属1を獲得'],
  232. ['鋼材1 《周辺探索》成功数0~1では鋼材[1D10×30]獲得', '資源アステロイド 推進剤200、鋼材200を獲得', '大資源アステロイド 推進剤300、鋼材300を獲得', '鋼材1 《周辺探索》成功数0~1では鋼材[1D10×30]獲得', '砕けた惑星核 希少金属3を獲得'],
  233. ['鋼材1 《周辺探索》成功数0~1では鋼材[1D10×30]獲得', '枯渇彗星核 実体弾攻撃でダメージ200を出すと推進剤600を獲得', '小惑星の欠片 ビーム攻撃でダメージ200を出すと鋼材600を獲得', '氷のアステロイド群 推進剤500を獲得', 'レアアースアステロイド 希少金属4を獲得'],
  234. ['鋼材1 《周辺探索》成功数0~1では鋼材[1D10×30]獲得', '放棄されたドローン 鋼材200、希少金属1を獲得', '希少金属アステロイド 希少金属2を獲得', '巨大アイスブロック 推進剤600を獲得', 'レアアースアステロイド 希少金属4を獲得'],
  235. ]
  236. ),
  237. 'TRST' => StellarLife2D10Table.new(
  238. 'お宝特徴表',
  239. '恐竜を模した(価値+3)', 'ヘビを模した(価値+1)', '魚を模した(価値+1)', 'イヌを模した(価値+1)', 'ウマを模した(価値+1)', 'ネズミを模した(価値+1)', 'ウサギを模した(価値+1)', 'クマを模した(価値+1)', 'ネコを模した(価値+1)', '鳥を模した(価値+2)',
  240. '触り心地の良い(価値+1)', 'ふかふかした(価値+1)', 'ふわふわの', '柔らかな', 'なめらかな', 'かすかに震える', 'とげとげした', '硬質な', 'ザラッとした', '持ちやすい(価値+1)',
  241. '美しい(価値+1)', 'きれいな', '麗しの(価値+1)', '華美な', '派手な', 'ほのかに発光する', '色とりどりの', '鮮やかな', '変化に富む', '可憐な(価値+1)',
  242. 'しゃべる(価値+1)', '泣き声がする', '鳴き声がする', '歌が聞こえる(価値+1)', '音を吸い込む', '静寂の', '聞き上手の', '良い音の', '共鳴する', '響きの良い(価値+1)',
  243. 'おいしい匂いがする(価値+1)', '血の匂いがする', '動物の匂いがする', '草いきれの匂いがする', '上品な香りがする(価値+1)', '目の醒める匂いがする', '甘い匂いがする', '柑橘系の香りがする', '清冽な香りがする', '安らぎの香りがする(価値+1)',
  244. '好意を感じさせる(価値+1)', '痛みを感じさせる', '怒りを感じさせる', '苦悶を感じさせる', '弱さを感じさせる', '癒やしを感じさせる(価値+1)', '母性を感じさせる', '優しさを感じさせる', '力強さを感じさせる', '年月を感じさせる(価値+1)',
  245. '洗練された(価値+1)', 'とろけるような', '不安定な', 'まろやかな', '穏やかな', '柔和な', 'オーガニックな(価値+1)', 'ストイックな', 'シンプルな', 'ナチュラルな(価値+1)',
  246. '気高き(価値+1)', '艶やかな', '気取った', '気位の高い', 'リッチな', '気品漂う', '高潔な', '格調高い(価値+1)', '典雅な', 'ロイヤルな(価値+1)',
  247. '闇に溶けるような(価値+1)', '血塗られた', '片翼の', '円環の', '「機関」の', 'オッドアイの', '片目の', '堕天使の', '二重人格の(価値+1)', '輝きを纏う(価値+1)',
  248. '秘密を持つ(価値+2)', 'いわく付きの(価値+1)', '歴史ある(価値+1)', '奪い合われた(価値+1)', '受け継がれた(価値+1)', '失われた文化の(価値+1)', '謎に満ちた(価値+1)', '廃墟で見つかった(価値+1)', 'あのシリーズの1つ(価値+1)', '寵愛を受けた(価値+3)'
  249. ),
  250. 'TRAT' => StellarLife2D10Table.new(
  251. 'お宝形容表',
  252. 'ブレスト(価値+3)', 'ホーリー(価値+1)', 'ワンダフル(価値+1)', 'シャイニング(価値+1)', 'スーパー(価値+1)', 'エクセレント(価値+1)', 'グロリアス(価値+1)', 'グレート(価値+1)', 'フラワリー(価値+1)', 'ミラクル(価値+2)',
  253. 'アース(価値+1)', 'サバンナ(価値+1)', 'マウンテン', 'リバー', 'フォレスト', 'ジャングル', 'デザート', 'ハイランド', 'レイク', 'オーシャン(価値+1)',
  254. 'スペース(価値+1)', 'コスモ', 'ワールド(価値+1)', 'ユニバーサル', 'スカイ', 'メテオール', 'コメット', 'ルナティック', 'プラネタリー', 'ステラー(価値+1)',
  255. 'アンティーク(価値+1)', 'エンシェント', 'オールド', 'エルダー(価値+1)', 'カスタム', 'レーテスト', 'アバンギャルド', 'アドバンスト', 'カティングエッジ', 'フューチャー(価値+1)',
  256. 'ダーク(価値+1)', 'ソイル', 'ウォーター', 'アイス', 'フィジカル(価値+1)', 'マインド', 'フレイム', 'ウィンド', 'サンダー', 'ライト(価値+1)',
  257. '闇の(価値+1)', '土の', '水の', '氷の', '物理', '心の(価値+1)', '炎の', '風の', '雷の', '光の(価値+1)',
  258. '骨董品の(価値+1)', 'いにしえの', '古き', '長老の', '特注', '最新型', '前衛的(価値+1)', '発展的', '先進的', '未来的(価値+1)',
  259. '宇宙(価値+1)', '乾坤', '世界', '森羅万象', '空の', '流星の', '隕石の', '月の(価値+1)', '惑星', '星の(価値+1)',
  260. '大地の(価値+1)', '草原の', '山の', '川の', '森の', '林の', '砂漠の', '高地の', '湖の(価値+1)', '海の(価値+1)',
  261. '祝福の(価値+2)', '神聖な(価値+1)', '不思議な(価値+1)', '輝かしい(価値+1)', '超(価値+1)', '素晴らしい(価値+1)', '栄光の(価値+1)', '偉大な(価値+1)', '華の(価値+1)', '奇跡の(価値+3)'
  262. ),
  263. 'TRMT' => StellarLife2D10Table.new(
  264. 'お宝外見表',
  265. 'ダイヤモンド(価値+3)', 'ジェイド(価値+1)', 'エメラルド(価値+1)', 'トパーズ(価値+1)', 'サファイア(価値+1)', 'ルビー(価値+1)', 'ガーネット(価値+1)', 'ラピスラズリ(価値+1)', 'アメジスト(価値+1)', 'スモーキークォーツ(価値+2)',
  266. 'ゴールデン(価値+1)', 'チタン(価値+1)', 'ブリキの', 'アイアン', 'スチール', '真鍮の', 'ブロンズ', 'カッパー', 'シルバー', 'プラチナ(価値+1)',
  267. 'マーブル(価値+1)', 'グラナイト', 'オブシディアン(価値+1)', 'スレート', 'ライムストーン', 'ガラス', 'リネン', 'ビロード', 'コットン', 'シルク(価値+1)',
  268. 'セラミック(価値+1)', 'プラスチック', 'レンガの', 'カーボン(価値+1)', 'コンクリート', 'クォーツの', 'オークの', 'レッドウッド', 'スプルースの', 'マホガニーの(価値+1)',
  269. 'ブラック(価値+1)', 'オレンジ', 'グレー', 'ブルー', 'マジェンタ(価値+1)', 'グリーン', 'レッド', 'パープル', 'イエロー', 'ホワイト(価値+1)',
  270. '黒い(価値+1)', '橙の', '灰色の', '青い', 'インディゴ', '緑の(価値+1)', '赤い', '紫の', '黄色い', '白い(価値+1)',
  271. '磁器の(価値+1)', '陶器の', '粘土の', '紙の', '石膏の', '水晶の', 'チークの(価値+1)', 'ヒノキの', '杉の', 'ウォルナット(価値+1)',
  272. '大理石の(価値+1)', '御影石の', '黒曜石の', '粘板岩の', '石灰岩の', '玻璃の', '麻の', '天鵞絨の(価値+1)', '綿の', '絹の(価値+1)',
  273. '黄金の(価値+1)', 'アルミニウム', '錫の', '鉄の', '鋼鉄の', '鉛の', '青銅の', '銅の', '銀の(価値+1)', '白金の(価値+1)',
  274. '金剛石の(価値+2)', '翡翠の(価値+1)', '翠玉の(価値+1)', '黄玉の(価値+1)', '蒼玉の(価値+1)', '紅玉の(価値+1)', '紅榴石の(価値+1)', '瑠璃の(価値+1)', '紫水晶の(価値+1)', '煙水晶の(価値+3)'
  275. ),
  276. 'TROT' => StellarLife2D10Table.new(
  277. 'お宝物品表',
  278. 'フルート(価値+3)', 'オカリナ(価値+1)', 'ギター(価値+1)', 'ピアノ(価値+1)', 'ドラム(価値+1)', 'ティンパニー(価値+1)', '太鼓(価値+1)', 'トランペット(価値+1)', 'ハープ(価値+1)', 'マイク(価値+2)',
  279. 'ブランコ(価値+1)', '人形(価値+1)', 'シーソー', 'ベンチ', 'すべり台', 'ラケット', 'ミニカー', 'コースター', 'ボール', 'オーブ(価値+1)',
  280. '皿(価値+1)', 'プレート', 'ティーセット(価値+1)', '箸', 'フォーク', 'スプーン', 'ナイフ', 'フライパン', '鍋', 'カップ(価値+1)',
  281. '王冠(価値+1)', '櫛', 'イヤリング', '首飾り(価値+1)', '腕輪', '指輪', 'ブローチ', 'サークレット', 'チョーカー', '羽飾り(価値+1)',
  282. 'ロッド(価値+1)', 'ウィップ', 'ハンマー', 'アックス', 'ブレイド(価値+1)', 'セイバー', 'シールド', 'クラブ', 'ランス', 'ソード(価値+1)',
  283. '錫杖(価値+1)', '鞭', '槌', '斧', '刃', '刀(価値+1)', '盾', '棍棒', '槍', '剣(価値+1)',
  284. '扇(価値+1)', 'ボトル', '燭台', 'ペン', '仮面', 'バッグ', '時計(価値+1)', '傘', '徽章', '鏡(価値+1)',
  285. 'スマートドレス(価値+1)', 'タッチパネル', 'インプットグローブ', 'プロジェクター', 'ディテクター', 'アナライザー', 'インジェクター', 'エアーボトル(価値+1)', 'ワイヤーロンチャー', 'ジェットパック(価値+1)',
  286. 'ランプ(価値+1)', 'ドア', '窓', '灯籠', '棚', 'キッチン', 'ソファ', '椅子', 'テーブル(価値+1)', 'ベッド(価値+1)',
  287. '人物像(価値+2)', 'フィギュア(価値+1)', 'モデル(価値+1)', '植物像(価値+1)', '動物像(価値+1)', 'レリーフ(価値+1)', 'オブジェ(価値+1)', 'ドーム(価値+1)', 'タペストリー(価値+1)', '絵画(価値+3)'
  288. ),
  289. 'TET' => StellarLifeD10_1to0_Table.new(
  290. '超未来の技術',
  291. '船の種、家の種、ビルの種:発達したバイオテクノロジーにより、光合成をしながらカーボン製品を作り出す「種」が作られました。土に植えると一軒家に育ったり、立派な木になってコップの実をならせたりします。',
  292. 'ワープリング:星と星の間を結ぶ空間のトンネルを作り出すのが、「ワープリング」です。中に入ると超光速で空間が周回しており、数時間から数日で数光年先の星に辿り着くことができます。',
  293. '擬似重力発生装置:超未来の宇宙船や宇宙ステーションでは、回転による遠心力などを活用して、擬似的に床に引っ張られる力を発生させています。パラメーターを変えれば、物の重さも体重も思いのままです。',
  294. 'アニマフォーム:ファブリックやマイクロマシンを使って作った人工の「動物」に、ネットワーク接続して「乗り移る」技術です。動物の姿で動物になりきって、自然の中を探索できます。',
  295. 'スマートテクスタイル:布やロープが自由自在に動きます。カーボンナノチューブなどの導電性の素材を織り込むことで繊維自体が電子機器として稼働・変形し、ボタンのセンサーと連動して様々な機能を果たします。',
  296. 'パーソナルバリア:人間の周囲を囲うバリアーで、身体の各所に付けた発生機から生まれた電磁フィールドが宇宙空間を飛び交う危険な宇宙線を防いでくれます。船外活動には必須の装備です。',
  297. 'フィンガーティップデザイン:指と手首を動かしながら頭の中でイメージを作ることで、あっという間に3D のデザインを作成できます。超未来は「繊維やケーブルが動く」ため、モノ作りがかなり複雑になっているのです。',
  298. 'ジェットパック:個人用の強力なジェット噴射機で、誰でも空に飛び上がることができます。長く使っていると高熱を発するので注意。宇宙空間では、これとスマートワイヤーを組み合わせて移動に使います。',
  299. 'メンタルプロジェクション:ヒトの心は、様々な価値観や性格が溶け合う複層的なもの。その複雑な姿を脳波投影で視界に映して、心の整理を付けやすくする技術です。しばしば「天使と悪魔」のビジュアルを付けます。',
  300. 'スライムソファ:球体状の大きなソファで、ポリマーとカーボン素材でできており、自在に変形させたり柔らかさを変えたりできます。床や壁に吸着してくれるため、無重力空間では身体を固定してくれます。'
  301. ),
  302. 'ENT' => StellarLifeD10_1to0_Table.new(
  303. '超未来のエンタメ',
  304. 'ホロシアター:劇場いっぱいにホログラムを展開して、広大な大地や美しい空の上などで大冒険のスペクタクルショーを「その場にいるような」臨場感で楽しむことができます。',
  305. 'アバターファイト!:手の平サイズの小型の人型アバターを思念で操って、ドームの中でバトルを楽しみます。フィールドはホログラム生成で、ビームやミサイルもホログラム再現なので、損傷の心配はありません。',
  306. 'VRゲーム:外接電脳さえ持っていれば、VRゴーグルがなくても仮想現実世界にダイブできます。圧倒的なリアリティを持つ仮想世界を堪能し、育成や対戦、パズルなど様々なゲームを楽しめます。',
  307. 'ハイド・アンド・シーク:惑星全域を舞台にしたかくれんぼです。第七感覚をフル活用して都市の全域を見て回り、ときには動物たちからも情報を集めながら、この星のどこかにいる鬼を見つけ出しましょう。',
  308. 'アロマバス:リラックスできる香りがいっぱいのお湯に浸かって、心身を癒やします。神経に疲れが溜まる超未来。ハーブの香りを思い切り吸い込んで、緊張を溶きほぐします。',
  309. 'ロジックパズル:外接電脳をフル活用しないと解けないような、難解なパズルに挑戦します。一見すると無関係な2つの要素を組み合わせることで、意外な手がかりが見つかります。',
  310. 'ホロアスレチック:コンクリートや植物性ビルなどを使って組み立てた殺風景なアスレチックを、ホログラムで美しくダイナミックに彩ります。超未来人の高い運動能力を存分に発揮できます。',
  311. 'スカイレース:超未来なので人は空を飛べます。トリブリードは自前の翼で、そうでなくても自分で設計したグライダーなどで、空中にホロ投影されるリングを通過しながら、複雑なコースを高速で飛びます。',
  312. 'ミステリーハウス:宝探しや事件解決など、規定時間以内に「謎」を解くイベントです。屋敷の中には手がかりが散りばめられており、VRでもリアルでも手軽に探偵遊びを楽しむことができます。',
  313. 'SNS:超未来のSNSは濃密にして苛烈!超高速でやり取りが行いながら、惑星の多くの人々と触れ合い交流を深めます。惑星ごとの微妙な文化の違いに注意を払いましょう。'
  314. ),
  315. 'CUT' => StellarLifeD10_1to0_Table.new(
  316. '超未来の文化',
  317. 'リスペクト・ユー:超未来の社会では、他人に対する「リスペクト」が何より大事にされています。見てもらうこと、尊敬されることを目指して、今日も人々はSNSで活動したり、働いたりします。',
  318. 'マインドミュージック:手を振るうことで感情を音色にする未来的な音楽です。VRやホログラフィと組み合わせれば映像効果も付き、思うままに自分の心から湧き出る音楽を演奏することができます。',
  319. 'レプロドュィーユ:オペラやバレエ、歌舞伎、ミュージカルといった歌劇の血筋を引いた文化です。物語や歴史の登場人物になりきって、身体の動きを正確に制御しつつ音楽を演奏して全身で表現を行います。',
  320. '物語:小説やアニメムービーなど、誰かが紡いだ物語を追体験します。星系によって異なる文化、異なるトレンドを持っているので、その違いもまた楽しめます。',
  321. 'Deep in myself:深い瞑想をします。静かな落ち着いた空間でゆっくりと精神を集中し、自分の心の中に潜るように意識の状態を変容させ、マインドフルネスを達成します。',
  322. 'ファッションコーデ:自然派やロマン風、モノトーンなど、統一感あるファッションは気品を感じさせます。今日のテーマはどうしましょうか。お部屋の家具も変形して、同じ系統にコーディネートしましょう。',
  323. '美術品:超未来の絵画や彫刻は、動きます。内部のカーボンナノファイバーやナノマシンが変形することで、あらかじめ制作者がプログラムした動きやインタラクティブな動きを繰り返します。',
  324. 'ガーデニング:平たい土地に植物や柵、椅子や机などの種を植えて、美しい庭を造成します。惑星ごとに異なる気候に適応した様々な固有種を使って、その惑星ならではの花の彩りを演出しましょう。',
  325. 'お料理!:超未来の合成肉や促成栽培野菜などを使って、舌を楽しませるおいしい料理を作りましょう。調理器具は3Dプリンターやクローナイフ、調味料は塩や砂糖、マイクロマシンに香辛料などです。',
  326. 'シリコンオフィス:角張ったオフィス机やタイムカードなど超未来の世界では絶滅しました。人々は家からでも公園からでも木の上や洞窟の中からでもワークに参加しますし、趣味と労働の区別を付けません。'
  327. ),
  328. 'NAT' => StellarLifeD10_1to0_Table.new(
  329. '超未来の自然',
  330. 'アニマルハート:動物たちの鳴き声の意味を解読し、また脳波分析を組み合わせることで、高等知能動物たちとある程度の意思疎通ができます。共通の話題は天気の話や景色の話、それにコイバナなど。',
  331. 'キャンプ:野外で夜を越すときは、キャンプをします。スマートテクスタイルを広げて雨風を避けるテントを作り、虫や鳥の鳴き声を聞きながら星空を眺めて一晩を過ごします。',
  332. 'ミネラルウォーター:テラフォーミングした惑星の海は、元の惑星のミネラル組成によって成分がだいぶ違ってきます。それほどしょっぱくない海もあれば、赤や緑っぽい海もあり。生息する魚等もまったく違います。',
  333. 'レイクサイド:クレーター等起伏のある地形に水が溜まってできた湖は、山裾の木々を鏡面のように反射して美麗な風景を作り出しています。中心部上層の澄んだ水は、簡単に浄化すれば飲み水にもできます。',
  334. '固有種:惑星に導入した動植物は、その惑星の環境に合わせて急速に独自の進化を遂げます。やたらにふわふわしたネコ科動物や雪の上に育つスノードロップ、転がって移動するアルマジロなどなど。',
  335. '枯れ草集め:都市部を離れると、エネルギー源はバイオ燃料に頼ることになります。地球以外の惑星には、基本的に石油や石炭など存在しません。燃料生成に使えそうな草木を集めましょう。',
  336. '山に進め:ジェットパックやスマートワイヤーがあるといっても、特に重力が強い惑星では高いところで大気が薄くなりやすく、山登りは大変なもの。しかしその分、山の上からの眺めは絶景です。',
  337. 'スカイハイ・ビュー:自然の環境ですばやく移動するには、グライダーや翼を使って滑空するのが手っ取り早いです。高い木や丘に上ってからジェットパック併用で舞い上がれば、空からの美しい景観も楽しめます。',
  338. '道なき森の道:惑星を覆う森の中には、基本的に整備された道はありません。空を見上げれば陽の光を遮る樹の冠。草をかき分け、花や草いきれの臭いを感じながら、ときには木の上を通って、先に進みます。',
  339. 'テラフォーミング:この銀河で、地球以外のすべての惑星はヒトが入植するために「テラフォーミング」したものです。水と大気を形成し、植物を育て、動物たちを導入し、長い年月を経て現在の姿になりました。'
  340. ),
  341. 'INT' => StellarLifeD10_1to0_Table.new(
  342. '超未来の宇宙船内',
  343. '甲板上でお茶を:狭い宇宙船に飽きてきたら、甲板の上に出て無限に広がる宇宙を感じることもできます。気圧0なので圧力ポットで持ってくる必要がありますが、星空を眺めながら飲むお茶は乙なものです。',
  344. 'マイクロマシン隔壁:宇宙船の隔壁はメタルナノカーボンやナノスチールでできていますが、補修のためにマイクロマシンが住んでいます。ときどき壁の端がちらちら動いて見えるのも、彼らのためかもしれません。',
  345. 'ダンベル100kg持てる:惑星環境と比べれば、宇宙船の擬似重力はどうしても弱くなるもの。筋力の衰えを防ぐために、部屋にトレーニングマシンを生成して筋トレをします。適度な負荷をかけましょう。',
  346. 'ユリカゴ:宇宙船に乗っている間は、多くの時間を宇宙船の居住スペース兼コントロールルームである「ユリカゴ」で過ごすことになります。たまにはホログラフィックで模様替えして気分を変えます。',
  347. '宇宙農法:数週間に渡る宇宙の旅では、食べ物や水は船内で育てます。マゼンダ色のLED ライトで植物やユーグレナを促成栽培し、バイオプラントでエネルギーゼリーを合成します。',
  348. 'メンテナンス:宇宙船は数多くのパーツでできているため、どこかが不具合や故障を起こすこともあります。基本的に自動制御で管理できますが、自分の目と外接電脳でもチェックを入れてみましょう。',
  349. '重力のムラ:宇宙船は擬似重力発生装置を持っており、床に足が付きますが、場所によって「重力」にムラがあります。身体が重いと感じたら、部屋の隅に行けば軽くなるかもしれません。',
  350. 'ワープ酔い:ワープ航法は空間の歪みを利用します。装甲が最も厚いユリカゴの中でも、ワープリングを出入りするときはグラっとくる感触があります。気分が悪くなったら、おとなしく寝ていましょう。',
  351. '1日25時間:宇宙船に「昼夜」はないため、照明を人工的に調整して生活サイクルを作ります。どうせ惑星ごとに1日の長さは違うので、24時間にこだわる必要はありません。自由に決めます。',
  352. 'スターリー・スカイ:惑星の明かりも大気もない宇宙船の上からは、星空を鮮やかに見ることができます。当然、星によって天球図も違います。月が2つや4つあったり、連星が見られたりします。'
  353. ),
  354. }.freeze
  355. 1 register_prefix(TABLES.keys)
  356. end
  357. end
  358. end

lib/bcdice/game_system/StrangerOfSwordCity.rb

96.77% lines covered

81.82% branches covered

62 relevant lines. 60 lines covered and 2 lines missed.
22 total branches, 18 branches covered and 4 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class StrangerOfSwordCity < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'StrangerOfSwordCity'
  7. # ゲームシステム名
  8. 1 NAME = '剣の街の異邦人TRPG'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'つるきのまちのいほうしんTRPG'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定 xSR or xSRy or xSR+y or xSR-y or xSR+y>=z
  14.  x=ダイス数、y=修正値(省略可、±省略時は+として扱う)、z=難易度(省略可)
  15.  判定時はクリティカル、ファンブルの自動判定を行います。
  16. ・通常のnD6ではクリティカル、ファンブルの自動判定は行いません。
  17. ・D66ダイスあり
  18. INFO_MESSAGE_TEXT
  19. 1 register_prefix('\d+SR')
  20. 1 def initialize(command)
  21. 33 super(command)
  22. 33 @sort_add_dice = true
  23. 33 @d66_sort_type = D66SortType::NO_SORT
  24. 33 @round_type = RoundType::FLOOR
  25. end
  26. 1 def eval_game_system_specific_command(command)
  27. 24 debug('eval_game_system_specific_command command', command)
  28. 24 command = command.upcase
  29. 24 result = checkRoll(command)
  30. 24 then: 24 else: 0 return result if result.instance_of?(Result)
  31. else: 0 then: 0 return result unless result.empty?
  32. return result
  33. end
  34. 1 def checkRoll(command)
  35. 24 debug("checkRoll begin command", command)
  36. 24 result = Result.new
  37. 24 result.text = ''
  38. 24 else: 24 then: 0 return result unless command =~ /^(\d+)SR([+-]?\d+)?(>=(\d+))?$/i
  39. 24 diceCount = Regexp.last_match(1).to_i
  40. 24 modify = Regexp.last_match(2).to_i
  41. 24 then: 19 else: 5 difficulty = Regexp.last_match(4).to_i if Regexp.last_match(4)
  42. 24 diceList = @randomizer.roll_barabara(diceCount, 6).sort
  43. 24 dice = diceList.sum()
  44. 24 totalValue = (dice + modify)
  45. 24 modifyText = getModifyText(modify)
  46. 24 result.text += "(#{command}) > #{dice}[#{diceList.join(',')}]#{modifyText} > #{totalValue}"
  47. 24 criticalResult = getCriticalResult(diceList)
  48. 24 else: 17 then: 7 unless criticalResult.nil?
  49. 7 result.critical = true
  50. 7 result.success = true
  51. 7 result.text += " > クリティカル(+#{criticalResult}D6)"
  52. 7 return result
  53. end
  54. 17 then: 5 else: 12 if isFumble(diceList, diceCount)
  55. 5 result.fumble = true
  56. 5 result.failure = true
  57. 5 result.text += ' > ファンブル'
  58. 5 return result
  59. end
  60. 12 else: 2 then: 10 unless difficulty.nil?
  61. 10 then: 5 if totalValue >= difficulty
  62. 5 result.success = true
  63. 5 result.text += ' > 成功'
  64. else: 5 else
  65. 5 result.failure = true
  66. 5 result.text += ' > 失敗'
  67. end
  68. end
  69. 12 return result
  70. end
  71. 1 def getModifyText(modify)
  72. 24 then: 19 else: 5 return "" if modify == 0
  73. 5 then: 2 else: 3 return modify.to_s if modify < 0
  74. 3 return "+#{modify}"
  75. end
  76. 1 def getCriticalResult(diceList)
  77. 109 dice6Count = diceList.select { |i| i == 6 }.size
  78. 24 then: 7 else: 17 if dice6Count >= 2
  79. 7 return dice6Count.to_s
  80. end
  81. 17 return nil
  82. end
  83. 1 def isFumble(diceList, diceCount)
  84. 68 (diceList.select { |i| i == 1 }.size >= diceCount)
  85. end
  86. end
  87. end
  88. end

lib/bcdice/game_system/StratoShout.rb

100.0% lines covered

83.33% branches covered

28 relevant lines. 28 lines covered and 0 lines missed.
6 total branches, 5 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class StratoShout < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'StratoShout'
  7. # ゲームシステム名
  8. 1 NAME = 'ストラトシャウト'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'すとらとしやうと'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. VOT, GUT, BAT, KEYT, DRT: (ボーカル、ギター、ベース、キーボード、ドラム)トラブル表
  14. EMO: 感情表
  15. ATn, RTTn: 特技表(n=分野。空:ランダム 1:主義 2:身体 3:モチーフ 4:エモーション 5:行動 6:逆境)
  16. RCT: 分野ランダム表
  17. SCENE, MACHI, GAKKO, BAND: (汎用、街角、学校、バンド)シーン表 接近シーンで使用
  18. TENKAI: シーン展開表 奔走シーン 練習シーンで使用
  19. D66入れ替えあり
  20. INFO_MESSAGE_TEXT
  21. 1 def initialize(command)
  22. 46 super(command)
  23. 46 @sort_add_dice = true
  24. 46 @d66_sort_type = D66SortType::ASC
  25. end
  26. 1 def result_2d6(_total, dice_total, _dice_list, cmp_op, _target)
  27. 10 else: 10 then: 0 return nil unless cmp_op == :>=
  28. 10 then: 2 if dice_total <= 2
  29. 2 else: 8 Result.fumble(translate("StratoShout.fumble"))
  30. 8 then: 2 else: 6 elsif dice_total >= 12
  31. 2 Result.critical(translate("StratoShout.critical"))
  32. end
  33. end
  34. 1 def eval_game_system_specific_command(command)
  35. 36 roll_tables(command, self.class::TABLES) || self.class::RTT.roll_command(@randomizer, command)
  36. end
  37. 1 class << self
  38. 1 private
  39. 1 def translate_tables(locale)
  40. {
  41. 2 "VOT" => DiceTable::Table.from_i18n("StratoShout.table.VOT", locale),
  42. "GUT" => DiceTable::Table.from_i18n("StratoShout.table.GUT", locale),
  43. "BAT" => DiceTable::Table.from_i18n("StratoShout.table.BAT", locale),
  44. "KEYT" => DiceTable::Table.from_i18n("StratoShout.table.KEYT", locale),
  45. "DRT" => DiceTable::Table.from_i18n("StratoShout.table.DRT", locale),
  46. "EMO" => DiceTable::Table.from_i18n("StratoShout.table.EMO", locale),
  47. "SCENE" => DiceTable::Table.from_i18n("StratoShout.table.SCENE", locale),
  48. "MACHI" => DiceTable::Table.from_i18n("StratoShout.table.MACHI", locale),
  49. "GAKKO" => DiceTable::Table.from_i18n("StratoShout.table.GAKKO", locale),
  50. "BAND" => DiceTable::Table.from_i18n("StratoShout.table.BAND", locale),
  51. "TENKAI" => DiceTable::D66Table.from_i18n("StratoShout.table.TENKAI", locale),
  52. }
  53. end
  54. 1 def translate_rtt(locale)
  55. 2 DiceTable::SaiFicSkillTable.from_i18n("StratoShout.RTT", locale, rtt: 'AT', rttn: ['AT1', 'AT2', 'AT3', 'AT4', 'AT5', 'AT6'])
  56. end
  57. end
  58. 1 TABLES = translate_tables(:ja_jp)
  59. 1 RTT = translate_rtt(:ja_jp)
  60. 1 register_prefix(TABLES.keys, RTT.prefixes)
  61. end
  62. end
  63. end

lib/bcdice/game_system/StratoShout_Korean.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/StratoShout"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class StratoShout_Korean < StratoShout
  6. # ゲームシステムの識別子
  7. 1 ID = 'StratoShout:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '스트라토 샤우트'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:스트라토 샤우트'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. VOT, GUT, BAT, KEYT, DRT: (보컬, 기타, 베이스, 키보드, 드럼)트러블표
  15. EMO: 감정표
  16. RTT[1-6], AT[1-6]: 특기표(공백: 랜덤 1: 가치관 2: 신체 3: 모티브 4: 이모션 5: 행동 6: 역경)
  17. SCENE, MACHI, GAKKO, BAND: (범용, 거리, 학교, 밴드)장면표. 접근 장면에 사용
  18. TENKAI: 장면 전개표. 분주 장면, 연습 장면에 사용
  19. []내는 생략가능 D66는 변동있음
  20. INFO_MESSAGE_TEXT
  21. 1 register_prefix_from_super_class()
  22. 1 def initialize(command)
  23. 23 super(command)
  24. 23 @locale = :ko_kr
  25. end
  26. 1 TABLES = translate_tables(:ko_kr).freeze
  27. 1 RTT = translate_rtt(:ko_kr)
  28. end
  29. end
  30. end

lib/bcdice/game_system/Strave.rb

100.0% lines covered

93.33% branches covered

63 relevant lines. 63 lines covered and 0 lines missed.
15 total branches, 14 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Strave < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Strave'
  7. # ゲームシステム名
  8. 1 NAME = '碧空のストレイヴ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'へきくうのすとれいふ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・モラトリアムフェイズ用判定:MPm
  14. ・命中判定:nSTm*p
  15. 「n」でダイス数を指定。
  16. 「m」で目標値を指定。省略は出来ません。
  17. 「p」で攻撃力を指定。「*」は「x」でも可。
  18. 【書式例】
  19. ・MP6 → 目標値6のモラトリアムフェイズ用判定。
  20. ・5ST6*10 → 5d10で目標値6、攻撃力10の命中判定。
  21. 【各種表】
  22. ・所属表:AFF  VN版:AFV
  23. ・アイデンティティ表:IDT  VN版:IDV
  24. ※アイデンティティ表はエラッタ適用済です。
  25. MESSAGETEXT
  26. 1 register_prefix(
  27. 'MP', '\d+ST',
  28. 'AFF', 'IDT', 'AFV', 'IDV'
  29. )
  30. 1 def initialize(command)
  31. 12 super(command)
  32. 12 @sort_add_dice = true # ダイスのソート有
  33. end
  34. 1 def eval_game_system_specific_command(command)
  35. output =
  36. 12 else: 0 case command.upcase
  37. # MPコマンド:モラトリアムフェイズ用判定
  38. when: 5 when /MP(\d+)$/i
  39. 5 diceCount = 2
  40. 5 target = Regexp.last_match(1).to_i
  41. 5 checkRoll(diceCount, target, nil)
  42. # STコマンド:命中判定
  43. when: 3 when /(\d+)ST(\d+)(x|\*)(\d+)$/i
  44. 3 diceCount = Regexp.last_match(1).to_i
  45. 3 target = Regexp.last_match(2).to_i
  46. 3 damage = (Regexp.last_match(4) || 0).to_i
  47. 3 checkRoll(diceCount, target, damage)
  48. # 各種表
  49. when: 1 when 'AFF'
  50. 1 get_affiliation_table
  51. when: 1 when 'IDT'
  52. 1 get_identity_table
  53. when: 1 when 'AFV'
  54. 1 get_affiliation_table2
  55. when: 1 when 'IDV'
  56. 1 get_identity_table2
  57. end
  58. 12 return output
  59. end
  60. 1 def checkRoll(diceCount, target, damage)
  61. 8 then: 1 else: 7 target = 1 if target < 1
  62. 8 then: 1 else: 7 target = 10 if target > 10
  63. 8 diceArray = @randomizer.roll_barabara(diceCount, 10).sort
  64. 8 diceText = diceArray.join(",")
  65. 34 successCount = diceArray.find_all { |i| (i <= target) }.size
  66. 8 isDamage = !damage.nil?
  67. 8 then: 3 if isDamage
  68. 3 totalDamage = successCount * damage
  69. 3 result = "(#{diceCount}D10\<\=#{target}) > #{diceText} > Hits:#{successCount}*#{damage} > #{totalDamage}ダメージ"
  70. else: 5 else
  71. 5 result = "(#{diceCount}D10\<\=#{target}) > #{diceText}"
  72. 5 then: 4 if successCount > 0
  73. 4 result += " > 【成功】"
  74. else: 1 else
  75. 1 result += " > 【失敗】"
  76. end
  77. end
  78. 8 return result
  79. end
  80. 1 def get_affiliation_table
  81. 1 name = '所属表:基本'
  82. table = [
  83. 1 [1, 'アリウス管理委員会:あなたはアリウス管理委員会に所属している。'],
  84. [2, 'オーヴァーブルー:あなたはオーヴァーブルーに所属している。'],
  85. [3, 'ウォルゲイト:あなたはウォルゲイトに所属している。'],
  86. [4, '暁部隊:あなたはかつて、反逆者・暁弥琴と同じ部隊に所属していた。'],
  87. [5, '天文部:あなたは天文部に所属している。'],
  88. [6, '吹奏楽部:あなたは吹奏楽部に所属している。'],
  89. [7, '剣道部:あなたは剣道部に所属している。'],
  90. [8, 'ボクシング部:あなたはボクシング部に所属している。'],
  91. [9, '陸上部:あなたは陸上部に所属している。'],
  92. [10, '茶道部:あなたは茶道部に所属している。'],
  93. [11, 'パソコン部:あなたはパソコン部に所属している。'],
  94. [12, '新聞部:あなたは新聞部に所属している。'],
  95. [13, '弓道部:あなたは弓道部に所属している。'],
  96. [14, '美術部:あなたは美術部に所属している。'],
  97. [15, 'ミリタリー研究会:あなたはミリタリー研究会に所属している。'],
  98. [16, '歴史研究会:あなたは歴史研究会に所属している。'],
  99. [17, 'ロボット研究会:あなたはロボット研究会に所属している。'],
  100. [18, '図書委員会:あなたは図書委員会に所属している。'],
  101. [19, '任意:あなたの任意の所属を設定せよ。'],
  102. [20, '任意:あなたの任意の所属を設定せよ。']
  103. ]
  104. 1 return get_strave_1d100_table_result(name, table)
  105. end
  106. 1 def get_identity_table
  107. 1 name = 'アイデンティティ表:基本'
  108. table = [
  109. 1 [1, '戦い:戦いこそが、あなたをあなたたらしめている。'],
  110. [2, '守護:あなたには守るべきものがある。'],
  111. [3, '復讐:あなたは復讐を誓っている。何かに、あるいは誰かに。'],
  112. [4, '名声:その身に浴びる脚光を、何よりも誉としている。'],
  113. [5, '恋愛:あなたはその身を焦がす恋に生きている。'],
  114. [6, '家族:あなたにとって、家族はかけがえの無いものだ。'],
  115. [7, '友人:あなたは友のために戦っている。'],
  116. [8, '部隊:共に戦う部隊の仲間が、あなたに力をくれる。'],
  117. [9, 'ストレイヴ:あなたは自身のストレイヴを誇りに思っている。'],
  118. [10, 'スフィアブレイク:あなたはスフィアブレイクを熱烈に目指している。'],
  119. [11, 'お金:あなたはお金を求めている。報酬こそが自分の価値だ。'],
  120. [12, '夢:あなたには夢がある。自分を突き動かす夢が。'],
  121. [13, '忠誠:あなたは忠誠を誓っている。何かに、あるいは誰かに。'],
  122. [14, '共生:あなたは、ヴァイエルと人類との共生を望んでいる。'],
  123. [15, '居場所:自身の居場所こそが、あなたに力をくれる。'],
  124. [16, '強制:あなたは不本意ながら今の立場にいる。'],
  125. [17, '碧空:見上げた青空が、あなたを変えた。'],
  126. [18, '任意:あなたの任意のアイデンティティを設定せよ。'],
  127. [19, '任意:あなたの任意のアイデンティティを設定せよ。'],
  128. [20, '任意:あなたの任意のアイデンティティを設定せよ。']
  129. ]
  130. 1 return get_strave_1d100_table_result(name, table)
  131. end
  132. 1 def get_affiliation_table2
  133. 1 name = '所属表:ヴァリアンスネイヴァー'
  134. table = [
  135. 1 [1, 'シュヴァレ・トワール:あなたはシュヴァレ・トワールに所属している。'],
  136. [2, 'ディープシンカー:あなたはディープシンカーに所属している。'],
  137. [3, 'ヴェルクシュタット:あなたはヴェルクシュタットに所属している。'],
  138. [4, 'アウスヴァル:あなたはアウスヴァルに所属している。'],
  139. [5, '美術科:あなたは美術科に所属している。'],
  140. [6, '哲学科:あなたは哲学科に所属している。'],
  141. [7, '数学科:あなたは数学科に所属している。'],
  142. [8, '地理学科:あなたは地理学科に所属している。'],
  143. [9, '工学科:あなたは工学科に所属している。'],
  144. [10, '体育学科:あなたは体育学科に所属している。'],
  145. [11, '農学科:あなたは農学科に所属している。'],
  146. [12, '歴史学科:あなたは歴史学科に所属している。'],
  147. [13, '医学科:あなたは医学科に所属している。'],
  148. [14, '情報学科:あなたは情報学科に所属している。'],
  149. [15, '音楽科:あなたは音楽科に所属している。'],
  150. [16, '心理学科:あなたは心理学科に所属している。'],
  151. [17, '文学科:あなたは文学科に所属している。'],
  152. [18, '任意:あなたの任意の所属を設定すること。'],
  153. [19, '任意:あなたの任意の所属を設定すること。'],
  154. [20, '任意:あなたの任意の所属を設定すること。']
  155. ]
  156. 1 return get_strave_1d100_table_result(name, table)
  157. end
  158. 1 def get_identity_table2
  159. 1 name = 'アイデンティティ表:ヴァリアンスネイヴァー'
  160. table = [
  161. 1 [1, '戦い:戦いへの衝動が、あなたをあなたたらしめている。'],
  162. [2, '守護:守るべきものの存在が、あなたをあなたたらしめている。'],
  163. [3, '復讐:復讐の誓いこそが、あなたをあなたたらしめている。'],
  164. [4, '名声:与えられた名誉こそが、あなたをあなたたらしめている。'],
  165. [5, '恋愛:愛する者への想いが、あなたをあなたたらしめている。'],
  166. [6, '家族:かけがえのない家族が、あなたをあなたたらしめている。'],
  167. [7, '友人:友の存在が、あなたをあなたたらしめている。'],
  168. [8, '部隊:部隊の戦友こそが、あなたをあなたたらしめている。'],
  169. [9, 'ストレイヴ:ストレイヴの存在が、あなたの心を保っている。'],
  170. [10, '宇宙:やがて来る旅立ちの日まで、あなたはあなたであろうとしている。'],
  171. [11, 'お金:与えられる報酬のため、あなたはあなたであろうとしている。'],
  172. [12, '夢:あなたには、己の心に誓った夢がある。'],
  173. [13, '忠誠:その心でもって、誓った忠義がある。'],
  174. [14, '共生:あなたは、ヴァイエルと人類との共生を望んでいる。'],
  175. [15, '居場所:自身の居場所への思いが、あなたをあなたたらしめている。'],
  176. [16, 'ヴァイエル:あなたと同じでありながら、あなたと異なる存在。彼らへの思いが、あなたをあなたたらしめている。'],
  177. [17, 'エコール:自身の生きる場所への思いが、あなたをあなたたらしめている。'],
  178. [18, '任意:あなたの任意のアイデンティティを設定せよ。'],
  179. [19, '任意:あなたの任意のアイデンティティを設定せよ。'],
  180. [20, '任意:あなたの任意のアイデンティティを設定せよ。']
  181. ]
  182. 1 return get_strave_1d100_table_result(name, table)
  183. end
  184. 1 def get_strave_1d100_table_result(name, table)
  185. 4 dice = @randomizer.roll_once(100)
  186. 4 dice2 = ((dice.to_i - 1) / 5).floor + 1
  187. 4 result = get_table_by_number(dice2, table)
  188. 4 return get_strave_table_result(name, dice, result)
  189. end
  190. 1 def get_strave_table_result(name, dice, result)
  191. 4 return "#{name}(#{dice}) > #{result}"
  192. end
  193. end
  194. end
  195. end

lib/bcdice/game_system/SwordWorld.rb

98.83% lines covered

93.94% branches covered

171 relevant lines. 169 lines covered and 2 lines missed.
66 total branches, 62 branches covered and 4 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/base"
  3. 1 require "bcdice/game_system/sword_world/rating_parser"
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class SwordWorld < Base
  7. # ゲームシステムの識別子
  8. 1 ID = 'SwordWorld'
  9. # ゲームシステム名
  10. 1 NAME = 'ソード・ワールドRPG'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = 'そおとわあると'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = "・SW レーティング表 (Kx[c]+m$f) (x:キー, c:クリティカル値, m:ボーナス, f:出目修正)\n"
  15. 1 register_prefix('H?K')
  16. 1 def initialize(command)
  17. 806 super(command)
  18. 806 @rating_table = 0
  19. end
  20. 1 def result_2d6(total, dice_total, _dice_list, cmp_op, target)
  21. 18 then: 4 if dice_total >= 12
  22. 4 else: 14 Result.critical(translate('SwordWorld.critical'))
  23. 14 then: 4 elsif dice_total <= 2
  24. 4 else: 10 Result.fumble(translate('SwordWorld.fumble'))
  25. 10 then: 6 elsif cmp_op != :>= || target == "?"
  26. 6 else: 4 nil
  27. 4 then: 2 elsif total >= target
  28. 2 Result.success(translate('success'))
  29. else: 2 else
  30. 2 Result.failure(translate('failure'))
  31. end
  32. end
  33. 1 def eval_game_system_specific_command(command)
  34. 600 rating(command)
  35. end
  36. 1 private
  37. 1 def rating_parser
  38. 444 return RatingParser.new
  39. end
  40. #################### SWレーティング表 ########################
  41. 1 def rating(string) # レーティング表
  42. 600 debug("rating string", string)
  43. 600 command = rating_parser.parse(string)
  44. 600 else: 598 then: 2 unless command
  45. 2 debug("not matched")
  46. 2 return '1'
  47. end
  48. # 2.0対応
  49. 598 rate_sw2_0 = getSW2_0_RatingTable
  50. 598 keyMax = rate_sw2_0.length - 1
  51. 598 debug("keyMax", keyMax)
  52. 598 then: 0 else: 598 if command.rate > keyMax
  53. return Result.new(translate('SwordWorld.keynumber_exceeds', keyMax: keyMax))
  54. end
  55. 598 then: 16 else: 582 if command.infinite_roll?
  56. 16 return Result.new(translate('SwordWorld.infinite_critical', min_critical: command.min_critical))
  57. end
  58. 582 newRates = getNewRates(rate_sw2_0)
  59. 582 output = "#{command} > "
  60. 582 diceResultTotals = []
  61. 582 diceResults = []
  62. 582 rateResults = []
  63. 582 dice = 0
  64. 582 diceOnlyTotal = 0
  65. 582 totalValue = 0
  66. 582 round = 0
  67. 582 first_to = command.first_to
  68. 582 first_modify = command.first_modify
  69. 582 first_modify_ssp = command.first_modify_ssp
  70. 582 loop do
  71. 3966 dice_raw, diceText = rollDice(command, round)
  72. 3966 dice = dice_raw
  73. 3966 then: 120 if first_to != 0
  74. 120 dice = dice_raw = first_to
  75. 120 else: 3846 first_to = 0
  76. 3846 then: 44 elsif first_modify != 0
  77. 44 dice += first_modify
  78. 44 else: 3802 first_modify = 0
  79. 3802 then: 3 else: 3799 elsif first_modify_ssp != 0
  80. 3 then: 2 else: 1 dice += first_modify_ssp if dice_raw <= 10
  81. 3 first_modify_ssp = 0
  82. end
  83. # 出目がピンゾロの時にはそこで終了
  84. 3966 then: 132 else: 3834 if dice_raw <= 2
  85. 132 diceResultTotals << dice_raw.to_s
  86. 132 diceResults << diceText.to_s
  87. 132 rateResults << "**"
  88. 132 round += 1
  89. 132 break
  90. end
  91. 3834 then: 40 else: 3794 dice += command.kept_modify if (command.kept_modify != 0) && (dice != 2)
  92. 3834 then: 0 else: 3834 dice = 2 if dice < 2
  93. 3834 then: 8 else: 3826 dice = 12 if dice > 12
  94. 3834 currentKey = (command.rate + round * command.rateup).clamp(0, keyMax)
  95. 3834 debug("currentKey", currentKey)
  96. 3834 rateValue = newRates[dice][currentKey]
  97. 3834 debug("rateValue", rateValue)
  98. 3834 totalValue += rateValue
  99. 3834 diceOnlyTotal += dice
  100. 3834 diceResultTotals << dice.to_s
  101. 3834 diceResults << diceText.to_s
  102. 3834 then: 3834 else: 0 rateResults << (dice > 2 ? rateValue : "**")
  103. 3834 round += 1
  104. 3834 else: 3384 then: 450 break unless dice >= command.critical
  105. end
  106. 582 result_text, critical, fumble = getResultText(
  107. totalValue, command, diceResults, diceResultTotals,
  108. rateResults, diceOnlyTotal, round
  109. )
  110. 582 output += result_text
  111. 582 return Result.new.tap do |r|
  112. 582 r.text = output
  113. 582 r.critical = critical
  114. 582 r.fumble = fumble
  115. end
  116. end
  117. 1 def getSW2_0_RatingTable
  118. 598 rate_sw2_0 = [
  119. # 0
  120. '*,0,0,0,1,2,2,3,3,4,4',
  121. '*,0,0,0,1,2,3,3,3,4,4',
  122. '*,0,0,0,1,2,3,4,4,4,4',
  123. '*,0,0,1,1,2,3,4,4,4,5',
  124. '*,0,0,1,2,2,3,4,4,5,5',
  125. '*,0,1,1,2,2,3,4,5,5,5',
  126. '*,0,1,1,2,3,3,4,5,5,5',
  127. '*,0,1,1,2,3,4,4,5,5,6',
  128. '*,0,1,2,2,3,4,4,5,6,6',
  129. '*,0,1,2,3,3,4,4,5,6,7',
  130. '*,1,1,2,3,3,4,5,5,6,7',
  131. # 11
  132. '*,1,2,2,3,3,4,5,6,6,7',
  133. '*,1,2,2,3,4,4,5,6,6,7',
  134. '*,1,2,3,3,4,4,5,6,7,7',
  135. '*,1,2,3,4,4,4,5,6,7,8',
  136. '*,1,2,3,4,4,5,5,6,7,8',
  137. '*,1,2,3,4,4,5,6,7,7,8',
  138. '*,1,2,3,4,5,5,6,7,7,8',
  139. '*,1,2,3,4,5,6,6,7,7,8',
  140. '*,1,2,3,4,5,6,7,7,8,9',
  141. '*,1,2,3,4,5,6,7,8,9,10',
  142. # 21
  143. '*,1,2,3,4,6,6,7,8,9,10',
  144. '*,1,2,3,5,6,6,7,8,9,10',
  145. '*,2,2,3,5,6,7,7,8,9,10',
  146. '*,2,3,4,5,6,7,7,8,9,10',
  147. '*,2,3,4,5,6,7,8,8,9,10',
  148. '*,2,3,4,5,6,8,8,9,9,10',
  149. '*,2,3,4,6,6,8,8,9,9,10',
  150. '*,2,3,4,6,6,8,9,9,10,10',
  151. '*,2,3,4,6,7,8,9,9,10,10',
  152. '*,2,4,4,6,7,8,9,10,10,10',
  153. # 31
  154. '*,2,4,5,6,7,8,9,10,10,11',
  155. '*,3,4,5,6,7,8,10,10,10,11',
  156. '*,3,4,5,6,8,8,10,10,10,11',
  157. '*,3,4,5,6,8,9,10,10,11,11',
  158. '*,3,4,5,7,8,9,10,10,11,12',
  159. '*,3,5,5,7,8,9,10,11,11,12',
  160. '*,3,5,6,7,8,9,10,11,12,12',
  161. '*,3,5,6,7,8,10,10,11,12,13',
  162. '*,4,5,6,7,8,10,11,11,12,13',
  163. '*,4,5,6,7,9,10,11,11,12,13',
  164. # 41
  165. '*,4,6,6,7,9,10,11,12,12,13',
  166. '*,4,6,7,7,9,10,11,12,13,13',
  167. '*,4,6,7,8,9,10,11,12,13,14',
  168. '*,4,6,7,8,10,10,11,12,13,14',
  169. '*,4,6,7,9,10,10,11,12,13,14',
  170. '*,4,6,7,9,10,10,12,13,13,14',
  171. '*,4,6,7,9,10,11,12,13,13,15',
  172. '*,4,6,7,9,10,12,12,13,13,15',
  173. '*,4,6,7,10,10,12,12,13,14,15',
  174. '*,4,6,8,10,10,12,12,13,15,15',
  175. # 51
  176. '*,5,7,8,10,10,12,12,13,15,15',
  177. '*,5,7,8,10,11,12,12,13,15,15',
  178. '*,5,7,9,10,11,12,12,14,15,15',
  179. '*,5,7,9,10,11,12,13,14,15,16',
  180. '*,5,7,10,10,11,12,13,14,16,16',
  181. '*,5,8,10,10,11,12,13,15,16,16',
  182. '*,5,8,10,11,11,12,13,15,16,17',
  183. '*,5,8,10,11,12,12,13,15,16,17',
  184. '*,5,9,10,11,12,12,14,15,16,17',
  185. '*,5,9,10,11,12,13,14,15,16,18',
  186. # 61
  187. '*,5,9,10,11,12,13,14,16,17,18',
  188. '*,5,9,10,11,13,13,14,16,17,18',
  189. '*,5,9,10,11,13,13,15,17,17,18',
  190. '*,5,9,10,11,13,14,15,17,17,18',
  191. '*,5,9,10,12,13,14,15,17,18,18',
  192. '*,5,9,10,12,13,15,15,17,18,19',
  193. '*,5,9,10,12,13,15,16,17,19,19',
  194. '*,5,9,10,12,14,15,16,17,19,19',
  195. '*,5,9,10,12,14,16,16,17,19,19',
  196. '*,5,9,10,12,14,16,17,18,19,19',
  197. # 71
  198. '*,5,9,10,13,14,16,17,18,19,20',
  199. '*,5,9,10,13,15,16,17,18,19,20',
  200. '*,5,9,10,13,15,16,17,19,20,21',
  201. '*,6,9,10,13,15,16,18,19,20,21',
  202. '*,6,9,10,13,16,16,18,19,20,21',
  203. '*,6,9,10,13,16,17,18,19,20,21',
  204. '*,6,9,10,13,16,17,18,20,21,22',
  205. '*,6,9,10,13,16,17,19,20,22,23',
  206. '*,6,9,10,13,16,18,19,20,22,23',
  207. '*,6,9,10,13,16,18,20,21,22,23',
  208. # 81
  209. '*,6,9,10,13,17,18,20,21,22,23',
  210. '*,6,9,10,14,17,18,20,21,22,24',
  211. '*,6,9,11,14,17,18,20,21,23,24',
  212. '*,6,9,11,14,17,19,20,21,23,24',
  213. '*,6,9,11,14,17,19,21,22,23,24',
  214. '*,7,10,11,14,17,19,21,22,23,25',
  215. '*,7,10,12,14,17,19,21,22,24,25',
  216. '*,7,10,12,14,18,19,21,22,24,25',
  217. '*,7,10,12,15,18,19,21,22,24,26',
  218. '*,7,10,12,15,18,19,21,23,25,26',
  219. # 91
  220. '*,7,11,13,15,18,19,21,23,25,26',
  221. '*,7,11,13,15,18,20,21,23,25,27',
  222. '*,8,11,13,15,18,20,22,23,25,27',
  223. '*,8,11,13,16,18,20,22,23,25,28',
  224. '*,8,11,14,16,18,20,22,23,26,28',
  225. '*,8,11,14,16,19,20,22,23,26,28',
  226. '*,8,12,14,16,19,20,22,24,26,28',
  227. '*,8,12,15,16,19,20,22,24,27,28',
  228. '*,8,12,15,17,19,20,22,24,27,29',
  229. '*,8,12,15,18,19,20,22,24,27,30',
  230. ]
  231. 598 return rate_sw2_0
  232. end
  233. 1 def getNewRates(rate_sw2_0)
  234. 582 rate_3 = []
  235. 582 rate_4 = []
  236. 582 rate_5 = []
  237. 582 rate_6 = []
  238. 582 rate_7 = []
  239. 582 rate_8 = []
  240. 582 rate_9 = []
  241. 582 rate_10 = []
  242. 582 rate_11 = []
  243. 582 rate_12 = []
  244. 582 zeroArray = []
  245. 582 rate_sw2_0.each do |rateText|
  246. 58782 rate_arr = rateText.split(/,/)
  247. 58782 zeroArray.push(0)
  248. 58782 rate_3.push(rate_arr[1].to_i)
  249. 58782 rate_4.push(rate_arr[2].to_i)
  250. 58782 rate_5.push(rate_arr[3].to_i)
  251. 58782 rate_6.push(rate_arr[4].to_i)
  252. 58782 rate_7.push(rate_arr[5].to_i)
  253. 58782 rate_8.push(rate_arr[6].to_i)
  254. 58782 rate_9.push(rate_arr[7].to_i)
  255. 58782 rate_10.push(rate_arr[8].to_i)
  256. 58782 rate_11.push(rate_arr[9].to_i)
  257. 58782 rate_12.push(rate_arr[10].to_i)
  258. end
  259. 582 else: 582 if @rating_table == 1
  260. then: 0 # 完全版準拠に差し替え
  261. rate_12[31] = rate_12[32] = rate_12[33] = 10
  262. end
  263. 582 newRates = [zeroArray, zeroArray, zeroArray, rate_3, rate_4, rate_5, rate_6, rate_7, rate_8, rate_9, rate_10, rate_11, rate_12]
  264. 582 return newRates
  265. end
  266. 1 def rollDice(_command, _round)
  267. 3854 dice_list = @randomizer.roll_barabara(2, 6)
  268. 3854 total = dice_list.sum()
  269. 3854 dice_str = dice_list.join(",")
  270. 3854 return total, dice_str
  271. end
  272. # @param rating_total [Integer]
  273. # @param command [SwordWorld::RatingParsed]
  274. # @param diceResults [Array<String>]
  275. # @param diceResultTotals [Array<String>]
  276. # @param rateResults [Array<String>]
  277. # @param dice_total [Integer]
  278. # @param round [Integer]
  279. # @return [Array(String, Boolean, Boolean)] output, critical, fumble
  280. 1 def getResultText(rating_total, command, diceResults, diceResultTotals,
  281. rateResults, dice_total, round)
  282. 582 sequence = []
  283. 582 sequence.push("2D:[#{diceResults.join(' ')}]=#{diceResultTotals.join(',')}")
  284. 582 then: 26 else: 556 if dice_total <= 2
  285. 26 sequence.push(rateResults.join(','))
  286. 26 sequence.push(translate("SwordWorld.fumble"))
  287. 26 return sequence.join(" > "), false, true
  288. end
  289. # rate回数が1回で、修正値がない時には途中式と最終結果が一致するので、途中式を省略する
  290. 556 then: 418 if rateResults.size > 1 || command.modifier != 0
  291. 418 text = rateResults.join(',') + Format.modifier(command.modifier)
  292. 418 then: 28 if command.half
  293. 28 text = "(#{text})/2"
  294. 28 then: 2 else: 26 if command.modifier_after_half != 0
  295. 2 text += Format.modifier(command.modifier_after_half)
  296. else: 390 end
  297. 390 then: 5 else: 385 elsif command.one_and_a_half
  298. 5 text = "(#{text})*1.5"
  299. 5 then: 1 else: 4 if command.modifier_after_one_and_a_half != 0
  300. 1 text += Format.modifier(command.modifier_after_one_and_a_half)
  301. end
  302. end
  303. 418 else: 138 sequence.push(text)
  304. 138 then: 26 elsif command.half
  305. 26 text = "#{rateResults.first}/2"
  306. 26 then: 4 else: 22 if command.modifier_after_half != 0
  307. 4 text += Format.modifier(command.modifier_after_half)
  308. end
  309. 26 else: 112 sequence.push(text)
  310. 112 then: 4 else: 108 elsif command.one_and_a_half
  311. 4 text = "#{rateResults.first}*1.5"
  312. 4 then: 1 else: 3 if command.modifier_after_one_and_a_half != 0
  313. 1 text += Format.modifier(command.modifier_after_one_and_a_half)
  314. end
  315. 4 sequence.push(text)
  316. end
  317. 556 then: 244 else: 312 if round > 1
  318. 244 round_text = translate("SwordWorld.round_text", reroll_count: round - 1)
  319. 244 sequence.push(round_text)
  320. end
  321. 556 total = rating_total + command.modifier
  322. 556 then: 54 if command.half
  323. 54 total = (total / 2.0).ceil
  324. 54 then: 6 else: 48 if command.modifier_after_half != 0
  325. 6 total += command.modifier_after_half
  326. else: 502 end
  327. 502 then: 9 else: 493 elsif command.one_and_a_half
  328. 9 total = (total * 1.5).ceil
  329. 9 then: 2 else: 7 if command.modifier_after_one_and_a_half != 0
  330. 2 total += command.modifier_after_one_and_a_half
  331. end
  332. end
  333. 556 total_text = total.to_s
  334. 556 sequence.push(total_text)
  335. 556 return sequence.join(" > "), round > 1, false
  336. end
  337. end
  338. end
  339. end

lib/bcdice/game_system/SwordWorld2_0.rb

98.15% lines covered

94.12% branches covered

54 relevant lines. 53 lines covered and 1 lines missed.
17 total branches, 16 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/arithmetic_evaluator'
  3. 1 require 'bcdice/game_system/SwordWorld'
  4. 1 require 'bcdice/game_system/sword_world/transcendent_test'
  5. 1 module BCDice
  6. 1 module GameSystem
  7. 1 class SwordWorld2_0 < SwordWorld
  8. # ゲームシステムの識別子
  9. 1 ID = 'SwordWorld2.0'
  10. # ゲームシステム名
  11. 1 NAME = 'ソード・ワールド2.0'
  12. # ゲームシステム名の読みがな
  13. 1 SORT_KEY = 'そおとわあると2.0'
  14. # ダイスボットの使い方
  15. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  16. 自動的成功、成功、失敗、自動的失敗の自動判定を行います。
  17. ・レーティング表 (Kx)
  18.  "Kキーナンバー+ボーナス"の形で記入します。
  19.  ボーナスの部分に「K20+K30」のようにレーティングを取ることは出来ません。
  20.  また、ボーナスは複数取ることが出来ます。
  21.  レーティング表もダイスロールと同様に、他のプレイヤーに隠れてロールすることも可能です。
  22.  例)K20   K10+5   k30   k10+10   Sk10-1   k10+5+2
  23. ・クリティカル値の設定
  24.  クリティカル値は"[クリティカル値]"で指定します。
  25.  指定しない場合はクリティカル値10とします。
  26.  クリティカル処理が必要ないときは13などとしてください。(防御時などの対応)
  27.  またタイプの軽減化のために末尾に「@クリティカル値」でも処理するようにしました。
  28.  例)K20[10]   K10+5[9]   k30[10]   k10[9]+10   k10-5@9
  29. ・レーティング表の半減 (HKx, KxH+N)
  30.  レーティング表の先頭または末尾に"H"をつけると、レーティング表を振って最終結果を半減させます。
  31.  末尾につけた場合、直後に修正ををつけることで、半減後の加減算を行うことができます。
  32.  この際、複数の項による修正にはカッコで囲うことが必要です(カッコがないとパースに失敗します)
  33.  クリティカル値を指定しない場合、クリティカルなしと扱われます。
  34.  例)HK20  K20h  HK10-5@9  K10-5@9H  K20gfH  K20+8H+2  K20+8H(1+1)
  35. ・ダイス目の修正(運命変転やクリティカルレイ用)
  36.  末尾に「$修正値」でダイス目に修正がかかります。
  37.  $+1と修正表記ならダイス目に+修正、$9のように固定値ならダイス目をその出目に差し替え。
  38.  クリティカルした場合でも固定値や修正値の適用は最初の一回だけです。
  39.  例)K20$+1   K10+5$9   k10-5@9$+2   k10[9]+10$9
  40. ・首切り刀用レーティング上昇 r10
  41.  例)K20r10 K30+24@8R10 K40+24@8$12r10
  42. ・グレイテストフォーチュンは末尾に gf
  43.  例)K20gf K30+24@8GF K40+24@8$12r10gf
  44. ・威力表を1d+sfで参照 クリティカル後も継続 sf4
  45.  例)k10sf4 k0+5SF4@13 k70+26sf3@9
  46. ・威力表を1d+tfで参照 クリティカル後は2dで参照 tf3
  47.  例)k10tf3 k0+5TF4@13 k70+26tf3@9
  48. ・超越判定用に2d6ロールに 2D6@10 書式でクリティカル値付与が可能に。
  49.  例)2D6@10 2D6@10+11>=30
  50. ・成長 (Gr)
  51.  末尾に数字を付加することで、複数回の成長をまとめて行えます。
  52.  例)Gr3
  53. ・防御ファンブル表 (FT)
  54.  防御ファンブル表を出すことができます。
  55. ・絡み効果表 (TT)
  56.  絡み効果表を出すことができます。
  57. INFO_MESSAGE_TEXT
  58. 1 register_prefix('H?K', 'Gr', '2D6?@\d+', 'FT', 'TT')
  59. 1 def initialize(command)
  60. 346 super(command)
  61. 346 @rating_table = 2
  62. end
  63. 1 def eval_game_system_specific_command(command)
  64. 316 case command
  65. when: 28 when /^Gr(\d+)?/i
  66. 28 then: 12 if command =~ /^Gr(\d+)/i
  67. 12 growth(Regexp.last_match(1).to_i)
  68. else: 16 else
  69. 16 growth
  70. end
  71. when: 84 when /^2D6?@\d+/i
  72. 84 transcendent_parser = Command::Parser.new(/2D6?/i, round_type: BCDice::RoundType::CEIL)
  73. .enable_critical
  74. .restrict_cmp_op_to(nil, :>=, :>)
  75. 84 cmd = transcendent_parser.parse(command)
  76. 84 else: 84 then: 0 unless cmd
  77. return nil
  78. end
  79. 84 node = TranscendentTest.new(cmd.critical, cmd.modify_number, cmd.cmp_op, cmd.target_number, @locale)
  80. 84 node.execute(@randomizer)
  81. when: 24 when 'FT'
  82. 24 get_fumble_table
  83. when: 24 when 'TT'
  84. 24 get_tangle_table
  85. else: 156 else
  86. 156 super(command)
  87. end
  88. end
  89. 1 def rating_parser
  90. 61 return RatingParser.new(version: :v2_0)
  91. end
  92. 1 def rollDice(command, round)
  93. 502 if command.semi_fixed_val > 0
  94. then: 50 # 常に片方の出目を固定
  95. 50 dice = @randomizer.roll_once(6)
  96. 50 else: 452 return dice + command.semi_fixed_val, "#{dice},#{command.semi_fixed_val}"
  97. 452 elsif round == 0 && command.tmp_fixed_val > 0
  98. then: 22 # 回転前だけ片方の出目を固定
  99. 22 dice = @randomizer.roll_once(6)
  100. 22 else: 430 return dice + command.tmp_fixed_val, "#{dice},#{command.tmp_fixed_val}"
  101. 430 elsif command.greatest_fortune
  102. then: 40 # グレイテスト・フォーチュン
  103. 40 dice = @randomizer.roll_once(6)
  104. 40 return dice * 2, "#{dice},#{dice}"
  105. else: 390 else
  106. 390 return super(command, round)
  107. end
  108. end
  109. 1 def growth(count = 1)
  110. 72 ((1..count).map { growth_step }).join " | "
  111. end
  112. 1 def growth_step
  113. 44 table = DiceTable::Table.from_i18n("SwordWorld2_0.GrowthTable", @locale)
  114. 44 r1 = table.roll(@randomizer)
  115. 44 r2 = table.roll(@randomizer)
  116. 44 then: 36 else: 8 return r1.value != r2.value ? "[#{r1.value},#{r2.value}]->(#{r1.body} or #{r2.body})" : "[#{r1.value},#{r2.value}]->(#{r1.body})"
  117. end
  118. 1 def get_fumble_table()
  119. 24 table = DiceTable::Table.from_i18n("SwordWorld2_0.FumbleTable", @locale)
  120. 24 return table.roll(@randomizer)
  121. end
  122. 1 def get_tangle_table()
  123. 24 table = DiceTable::Table.from_i18n("SwordWorld2_0.TangleTable", @locale)
  124. 24 return table.roll(@randomizer)
  125. end
  126. end
  127. end
  128. end

lib/bcdice/game_system/SwordWorld2_0_SimplifiedChinese.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/SwordWorld2_0'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class SwordWorld2_0_SimplifiedChinese < SwordWorld2_0
  6. # ゲームシステムの識別子
  7. 1 ID = 'SwordWorld2.0:SimplifiedChinese'
  8. # ゲームシステム名
  9. 1 NAME = '剑世界2.0'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Simplified Chinese:剑世界2.0'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. 自动成功、成功、失败、自动失败会自动判定。
  15. ・威力表 (Kx)
  16.  指令为“K威力值+加值”的格式。
  17.  加值的部分不能是像“K20+K30”这样的威力的写法。
  18.  另外,加值可以有多个。
  19.  威力表和骰点一样,可以对其他玩家隐藏。
  20.  例)K20   K10+5   k30   k10+10   Sk10-1   k10+5+2
  21. ・暴击值的设定
  22.  暴击值通过“[暴击值]”指定。
  23.  没有指定暴击值时默认为10。
  24.  如果不需要发生暴击,请设定为13。(例如防御时)
  25.  另外也可写成结尾的“@暴击值”的形式。
  26.  例)K20[10]   K10+5[9]   k30[10]   k10[9]+10   k10-5@9
  27. ・威力表的减半 (HKx, KxH+N)
  28.  在威力表开头或末尾加上“H”,骰威力表的最终结果就会减半。
  29.  H写在威力表末尾的情况下可以在后面直接跟着修正,会在减半后进行加减运算。
  30.  这种情况下,多个修正需要用括号括起来(否则会解析失败)
  31.  没有指定暴击值的情况下,则视为没有暴击值。
  32.  例)HK20  K20h  HK10-5@9  K10-5@9H  K20gfH  K20+8H+2  K20+8H+(1+1)
  33. ・骰子出目修正(命运变转或重击光辉用)
  34.  在指令末尾添加“$修正值”来改变骰子出目。
  35.  可以使用$+1的格式在骰子出目上+修正,或使用$9的格式把骰子出目替换为固定值。
  36.  暴击时只有第一次出目应用这个修正。
  37.  例)K20$+1   K10+5$9   k10-5@9$+2   k10[9]+10$9
  38. ・威力上升(斩首刀用) r10
  39.  r后跟上升值,暴击后威力上升r后所填写的上升值点
  40.  例)K20r10 K30+24@8R10 K40+24@8$12r10
  41. ・极限命运在末尾加上 gf
  42.  例)K20gf K30+24@8GF K40+24@8$12r5gf
  43. ・威力表使用1d+固定值对应 暴击后仍继续 sf4
  44.  例)k10sf4 k0+5sf4@13 k70+26sf3@9
  45. ・威力表使用1d+固定值对应 暴击后变回使用2d对应 tf3
  46.  例)k10tf3 k0+5tf4@13 k70+26tf3@9
  47. ・超越判定用2d6可写成 2d6@10 的格式加上暴击值。
  48.  例)2D6@10 2D6@10+11>=30
  49. ・成长 (Gr)
  50.  在Gr后面加上数字可以进行多次成长。
  51.  例)Gr3
  52. ・防御大失败表 (FT)
  53.  抽取防御大失败表。
  54. ・缠绕效果表 (TT)
  55.  抽取缠绕效果表。
  56. INFO_MESSAGE_TEXT
  57. 1 register_prefix_from_super_class()
  58. 1 def initialize(command)
  59. 73 super(command)
  60. 73 @locale = :zh_hans
  61. end
  62. end
  63. end
  64. end

lib/bcdice/game_system/SwordWorld2_5.rb

97.44% lines covered

83.33% branches covered

39 relevant lines. 38 lines covered and 1 lines missed.
12 total branches, 10 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/SwordWorld2_0'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class SwordWorld2_5 < SwordWorld2_0
  6. # ゲームシステムの識別子
  7. 1 ID = 'SwordWorld2.5'
  8. # ゲームシステム名
  9. 1 NAME = 'ソード・ワールド2.5'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'そおとわあると2.5'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. 自動的成功、成功、失敗、自動的失敗の自動判定を行います。
  15. ・レーティング表 (Kx)
  16.  "Kキーナンバー+ボーナス"の形で記入します。
  17.  ボーナスの部分に「K20+K30」のようにレーティングを取ることは出来ません。
  18.  また、ボーナスは複数取ることが出来ます。
  19.  レーティング表もダイスロールと同様に、他のプレイヤーに隠れてロールすることも可能です。
  20.  例)K20   K10+5   k30   k10+10   Sk10-1   k10+5+2
  21. ・クリティカル値の設定
  22.  クリティカル値は"[クリティカル値]"で指定します。
  23.  指定しない場合はクリティカル値10とします。
  24.  クリティカル処理が必要ないときは13などとしてください。(防御時などの対応)
  25.  またタイプの軽減化のために末尾に「@クリティカル値」でも処理するようにしました。
  26.  例)K20[10]   K10+5[9]   k30[10]   k10[9]+10   k10-5@9
  27. ・レーティング表の半減 (HKx, KxH+N)
  28.  レーティング表の先頭または末尾に"H"をつけると、レーティング表を振って最終結果を半減させます。
  29.  末尾につけた場合、直後に修正ををつけることで、半減後の加減算を行うことができます。
  30.  この際、複数の項による修正にはカッコで囲うことが必要です(カッコがないとパースに失敗します)
  31.  クリティカル値を指定しない場合、クリティカルなしと扱われます。
  32.  例)HK20  K20h  HK10-5@9  K10-5@9H  K20gfH  K20+8H+2  K20+8H+(1+1)
  33. ・レーティング表の1.5倍 (OHKx, KxOH+N)
  34.  レーティング表の先頭または末尾に"OH"をつけると、レーティング表を振って最終結果を1.5倍します。
  35.  末尾につけた場合、直後に修正ををつけることで、1.5倍後の加減算を行うことができます。
  36.  この際、複数の項による修正にはカッコで囲うことが必要です(カッコがないとパースに失敗します)
  37.  クリティカル値を指定しない場合、クリティカルなしと扱われます。
  38.  例)OHK20  K20oh  OHK10-5@9  K20+8OH+2  K20+8OH+(1+1)
  39. ・ダイス目の修正(運命変転やクリティカルレイ、魔女の火用)
  40.  末尾に「$修正値」でダイス目に修正がかかります。
  41.  $+1と修正表記ならダイス目に+修正、$9のように固定値ならダイス目をその出目に差し替え。
  42.  $~+1とチルダを追加して記述することで、出目10以下の場合のみダイス目に+修正(魔女の火用)
  43.  クリティカルした場合でも固定値や修正値の適用は最初の一回だけです。
  44.  例)K20$+1   K10+5$9   k10-5@9$+2   k10[9]+10$9   k20+6$~+1
  45. ・ダイス目の修正(必殺攻撃用)
  46.  「#修正値」でダイス目に修正がかかります。
  47.  クリティカルした場合でも修正値の適用は継続されます。
  48.  例)K20#1   k10-5@9#2
  49. ・首切り刀用レーティング上昇 r5
  50.  例)K20r5 K30+24@8R5 K40+24@8$12r5
  51. ・グレイテストフォーチュンは末尾に gf
  52.  例)K20gf K30+24@8GF K40+24@8$12r5gf
  53. ・威力表を1d+sfで参照 クリティカル後も継続 sf4
  54.  例)k10sf4 k0+5sf4@13 k70+26sf3@9
  55. ・威力表を1d+tfで参照 クリティカル後は2dで参照 tf3
  56.  例)k10tf3 k0+5tf4@13 k70+26tf3@9
  57. ・超越判定用に2d6ロールに 2D6@10 書式でクリティカル値付与が可能に。
  58.  例)2D6@10 2D6@10+11>=30
  59. ・成長 (Gr)
  60.  末尾に数字を付加することで、複数回の成長をまとめて行えます。
  61.  例)Gr3
  62. ・防御ファンブル表 (FT)
  63.  防御ファンブル表を出すことができます。
  64. ・絡み効果表 (TT)
  65.  絡み効果表を出すことができます。
  66. ・ドルイドの物理魔法用表 (Dru[2-6の値,7-9の値,10-12の値])
  67.  例)Dru[0,3,6]+10-3
  68. ・アビスカース表 (ABT)
  69.  アビスカース表を出すことができます。
  70. INFO_MESSAGE_TEXT
  71. 1 register_prefix('H?K', 'OHK', 'Gr', '2D6?@\d+', 'FT', 'TT', 'Dru', 'ABT')
  72. 1 def eval_game_system_specific_command(command)
  73. 199 case command
  74. when: 18 when /^dru\[(\d+),(\d+),(\d+)\]/i
  75. 18 power_list = Regexp.last_match.captures.map(&:to_i)
  76. 18 druid_parser = Command::Parser.new(/dru\[\d+,\d+,\d+\]/i, round_type: BCDice::RoundType::CEIL)
  77. 18 cmd = druid_parser.parse(command)
  78. 18 else: 18 then: 0 unless cmd
  79. return nil
  80. end
  81. 18 druid_dice(cmd, power_list)
  82. when: 8 when 'ABT'
  83. 8 get_abyss_curse_table
  84. else: 173 else
  85. 173 super(command)
  86. end
  87. end
  88. 1 def rating_parser
  89. 95 return RatingParser.new(version: :v2_5)
  90. end
  91. 1 def druid_dice(command, power_list)
  92. 18 dice_list = @randomizer.roll_barabara(2, 6)
  93. 18 dice_total = dice_list.sum()
  94. offset =
  95. 18 else: 0 case dice_total
  96. when: 4 when 2..6
  97. 4 0
  98. when: 8 when 7..9
  99. 8 1
  100. when: 6 when 10..12
  101. 6 2
  102. end
  103. 18 power = power_list[offset]
  104. 18 total = power + command.modify_number
  105. sequence = [
  106. 18 "(#{command.command.capitalize}#{Format.modifier(command.modify_number)})",
  107. "2D[#{dice_list.join(',')}]=#{dice_total}",
  108. "#{power}#{Format.modifier(command.modify_number)}",
  109. total
  110. ]
  111. 18 return sequence.join(" > ")
  112. end
  113. 1 def get_abyss_curse_table
  114. 8 table_result = DiceTable::D66GridTable.from_i18n('SwordWorld2_5.AbyssCurseTable', @locale).roll(@randomizer)
  115. additional =
  116. 8 else: 4 case table_result.value
  117. when: 2 when 14 # 「差別の」における分類決定表
  118. 2 DiceTable::D66ParityTable.from_i18n('SwordWorld2_5.AbyssCurseCategoryTable', @locale).roll(@randomizer).to_s
  119. when: 2 when 25 # 「過敏な」における属性決定表
  120. 2 DiceTable::D66ParityTable.from_i18n('SwordWorld2_5.AbyssCurseAttrTable', @locale).roll(@randomizer).to_s
  121. end
  122. final_result = [
  123. 8 table_result.to_s,
  124. additional,
  125. ].compact
  126. 8 return final_result.join("\n")
  127. end
  128. end
  129. end
  130. end

lib/bcdice/game_system/SwordWorld2_5_SimplifiedChinese.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/SwordWorld2_5'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class SwordWorld2_5_SimplifiedChinese < SwordWorld2_5
  6. # ゲームシステムの識別子
  7. 1 ID = 'SwordWorld2.5:SimplifiedChinese'
  8. # ゲームシステム名
  9. 1 NAME = '剑世界2.5'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Simplified Chinese:剑世界2.5'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. 自动成功、成功、失败、自动失败会自动判定。
  15. ・威力表 (Kx)
  16.  指令为“K威力值+加值”的格式。
  17.  加值的部分不能是像“K20+K30”这样的威力的写法。
  18.  另外,加值可以有多个。
  19.  威力表和骰点一样,可以对其他玩家隐藏。
  20.  例)K20   K10+5   k30   k10+10   Sk10-1   k10+5+2
  21. ・暴击值的设定
  22.  暴击值通过“[暴击值]”指定。
  23.  没有指定暴击值时默认为10。
  24.  如果不需要发生暴击,请设定为13。(例如防御时)
  25.  另外也可写成结尾的“@暴击值”的形式。
  26.  例)K20[10]   K10+5[9]   k30[10]   k10[9]+10   k10-5@9
  27. ・威力表的减半 (HKx, KxH+N)
  28.  在威力表开头或末尾加上“H”,骰威力表的最终结果就会减半。
  29.  H写在威力表末尾的情况下可以在后面直接跟着修正,会在减半后进行加减运算。
  30.  这种情况下,多个修正需要用括号括起来(否则会解析失败)
  31.  没有指定暴击值的情况下,则视为没有暴击值。
  32.  例)HK20  K20h  HK10-5@9  K10-5@9H  K20gfH  K20+8H+2  K20+8H+(1+1)
  33. ・骰子出目修正(命运变转或重击光辉用)
  34.  在指令末尾添加“$修正值”来改变骰子出目。
  35.  可以使用$+1的格式在骰子出目上+修正,或使用$9的格式把骰子出目替换为固定值。
  36.  暴击时只有第一次出目应用这个修正。
  37.  例)K20$+1   K10+5$9   k10-5@9$+2   k10[9]+10$9
  38. ・骰子出目修正(必杀攻击用)
  39.  写成“#修正值“的格式来增加骰子出目。
  40.  暴击时后续骰子也会继续应用修正值。
  41.  例)K20#1   k10-5@9#2
  42. ・威力上升(斩首刀用) r5
  43.  r后跟上升值,暴击后威力上升r后所填写的上升值点
  44.  例)K20r5 K30+24@8R5 K40+24@8$12r5
  45. ・极限命运在末尾加上 gf
  46.  例)K20gf K30+24@8GF K40+24@8$12r5gf
  47. ・威力表使用1d+固定值对应 暴击后仍继续 sf4
  48.  例)k10sf4 k0+5sf4@13 k70+26sf3@9
  49. ・威力表使用1d+固定值对应 暴击后变回使用2d对应 tf3
  50.  例)k10tf3 k0+5tf4@13 k70+26tf3@9
  51. ・超越判定用2d6可写成 2d6@10 的格式加上暴击值。
  52.  例)2D6@10 2D6@10+11>=30
  53. ・成长 (Gr)
  54.  在Gr后面加上数字可以进行多次成长。
  55.  例)Gr3
  56. ・防御大失败表 (FT)
  57.  抽取防御大失败表。
  58. ・缠绕效果表 (TT)
  59.  抽取缠绕效果表。
  60. ・德鲁伊用物理魔法表 (Dru[2~6的结果,7~9的结果,10~12的结果])
  61.  例)Dru[0,3,6]+10-3
  62. ・奈落诅咒表 (ABT)
  63.  抽取奈落诅咒表。
  64. INFO_MESSAGE_TEXT
  65. 1 register_prefix_from_super_class()
  66. 1 def initialize(command)
  67. 92 super(command)
  68. 92 @locale = :zh_hans
  69. end
  70. end
  71. end
  72. end

lib/bcdice/game_system/SwordWorld_SimplifiedChinese.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/SwordWorld'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class SwordWorld_SimplifiedChinese < SwordWorld
  6. # ゲームシステムの識別子
  7. 1 ID = 'SwordWorld:SimplifiedChinese'
  8. # ゲームシステム名
  9. 1 NAME = '剑世界'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Simplified Chinese:剑世界'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = "・SW 威力表 (Kx[c]+m$f) (x:威力值, c:暴击值, m:加值, f:骰子出目修正)\n"
  14. 1 register_prefix_from_super_class()
  15. 1 def initialize(command)
  16. 230 super(command)
  17. 230 @locale = :zh_hans
  18. end
  19. end
  20. end
  21. end

lib/bcdice/game_system/TalesFromTheLoop.rb

100.0% lines covered

90.0% branches covered

34 relevant lines. 34 lines covered and 0 lines missed.
10 total branches, 9 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class TalesFromTheLoop < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "TalesFromTheLoop"
  7. # ゲームシステム名
  8. 1 NAME = "ザ・ループTRPG"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "さるうふTRPG"
  11. 1 HELP_MESSAGE = <<~TEXT
  12. ■ 判定コマンド(nTFLx-x+x or nTFLx+x-x)
  13. (必要成功数)TFL(判定ダイス数)+/-(修正ダイス数)
  14. ※ 必要成功数と修正ダイス数は省略可能
  15. 例1) 必要成功数1、判定ダイスは能力値3
  16. 1TFL3
  17. 例2)必要成功数不明、あるいはダイスボットの成功判定を使わない、判定ダイスは能力値3+技能1で4、アイテムの修正+1
  18. TFL4+1
  19. 例3)必要成功数1、判定ダイスは能力値2+技能1で3、コンディションにチェックが2つ、アイテムの修正+1
  20. 1TFL3-2+1
  21. あるいは以下のようにカッコ書きで内訳を詳細に記述することも可能。
  22. 1TFL(2+1)-(1+1)+1
  23. 修正ダイスのプラスとマイナスは逆でもよい。
  24. 1TFL(2+1)+1-(1+1)
  25. TEXT
  26. 1 register_prefix('(\d+)?(TFL)')
  27. 1 def eval_game_system_specific_command(command)
  28. 42 parser = Command::Parser.new(/\d*TFL\d+/, round_type: round_type)
  29. 42 parsed = parser.parse(command)
  30. 42 else: 42 then: 0 return nil unless parsed
  31. 42 difficulty, dice_pool = parsed.command.split("TFL", 2).map(&:to_i)
  32. 42 dice_pool += parsed.modify_number
  33. 42 then: 7 else: 35 if dice_pool <= 0
  34. 7 dice_pool = 1
  35. end
  36. 42 ability_dice_text, success_dice = make_dice_roll(dice_pool)
  37. 42 return make_dice_roll_text(difficulty, dice_pool, ability_dice_text, success_dice)
  38. end
  39. 1 private
  40. 1 def make_dice_roll_text(difficulty, dice_pool, ability_dice_text, success_dice)
  41. 42 dice_count_text = "(#{dice_pool}D6) > #{ability_dice_text} 成功数:#{success_dice}"
  42. 42 push_dice = (dice_pool - success_dice)
  43. 42 then: 39 else: 3 if push_dice > 0
  44. 39 dice_count_text = "#{dice_count_text} 振り直し可能:#{push_dice}"
  45. 39 reroll_command = "\n振り直しコマンド: TFL#{push_dice}"
  46. end
  47. 42 then: 22 else: 20 if difficulty > 0
  48. 22 then: 13 if success_dice >= difficulty
  49. 13 return Result.success("#{dice_count_text} 成功!#{reroll_command}")
  50. else: 9 else
  51. 9 return Result.failure("#{dice_count_text} 失敗!#{reroll_command}")
  52. end
  53. end
  54. 20 return "#{dice_count_text}#{reroll_command}"
  55. end
  56. 1 def make_dice_roll(dice_pool)
  57. 42 dice_list = @randomizer.roll_barabara(dice_pool, 6)
  58. 42 success_dice = dice_list.count(6)
  59. 42 return "[#{dice_list.join(',')}]", success_dice
  60. end
  61. end
  62. end
  63. end

lib/bcdice/game_system/TenkaRyouran.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/SRS'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class TenkaRyouran < SRS
  6. # ゲームシステムの識別子
  7. 1 ID = 'TenkaRyouran'
  8. # ゲームシステム名
  9. 1 NAME = '天下繚乱'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'てんかりようらん'
  12. # 固有のコマンドの接頭辞を設定する
  13. 1 register_prefix('2D6', 'TR')
  14. # 成功判定のエイリアスコマンドを設定する
  15. 1 set_aliases_for_srs_roll('TR')
  16. 1 HELP_MESSAGE = help_message()
  17. end
  18. end
  19. end

lib/bcdice/game_system/TensaiGunshiNiNaro.rb

100.0% lines covered

100.0% branches covered

92 relevant lines. 92 lines covered and 0 lines missed.
30 total branches, 30 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class TensaiGunshiNiNaro < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'TensaiGunshiNiNaro'
  7. # ゲームシステム名
  8. 1 NAME = '天才軍師になろう'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'てんさいくんしになろう'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・行為判定
  14. TN6…「有利」を得ていない場合、6面ダイスを2つ振って判定します。
  15. TN10…「有利」を得ている場合、10面ダイスを2つ振って判定します。
  16. 不調 気づかぬうちの不満【C】…このセッションの間、「4」の出目を出しても判定は成功になりません。数字の後ろに【C】をつけます。
  17.  例)TN6C
  18. 軍師スキル 〇〇サポート【S】…決戦フェイズの判定中「3」の出目を出しても判定に成功します。数字の後ろに【S】をつけます。
  19.  例)TN6S
  20. 英傑スキル/武人 煌めく刃【B】…決戦フェイズの判定中「3」の出目を出しても判定に成功となり、スペシャルが発生します。数字の後ろに【B】をつけます。
  21.  例)TN6B
  22. 英傑スキル/武人 力ずく…その判定のサイコロをすべて振った後、[使用者の【攻撃力】]個サイコロを振る。先頭に使用者の【攻撃力】をつけます。
  23.  例)4TN6
  24. 英傑スキル/武人 必殺の剣【D】…《戦技》を使用している判定中「4」「5」の出目を出してもスペシャルが発生します。数字の後ろに【D】をつけます。
  25.  例)TN6K
  26. 英傑スキル/武人 二刀流【T】…「攻撃」のスキルの判定中「2」の出目を出しても判定に成功となり、同じ出目のサイコロが2つ以上出ているとスペシャルが発生します。数字の後ろに【T】をつけます。
  27.  例)TN6T
  28. 英傑スキル/カリスマ 御身のためならば【Y】…「交流」「スカウト」の判定中「3」の出目を出しても判定に成功となり、スペシャルが発生します。数字の後ろに【Y】をつけます。
  29.  例)TN6Y
  30. 英傑スキル/弓取り 愛用の弓【A】…「攻撃」のスキルの判定中「3」の出目を出しても判定に成功となり、スペシャルが発生します。数字の後ろに【A】をつけます。
  31.  例)TN6A
  32. 英傑スキル/ヤンキー&マイルドヤンキー その辺の物を武器に【C】…「4」の出目を出しても判定は成功になりません。数字の後ろに【C】をつけます。
  33.  例)TN6C
  34. 英傑スキル/ヤンキー&マイルドヤンキー 熱血判定【C】…「4」の出目を出しても判定は成功になりません。数字の後ろに【C】をつけます。
  35.  例)TN6C
  36. 英傑スキル/英傑汎用 凄腕エージェント【A】…活動フェイズの判定中「3」の出目を出しても判定に成功となり、スペシャルが発生します。数字の後ろに【A】をつけます。
  37.  例)TN6A
  38. 数字の後ろに複数のコマンドを追加できます。
  39.  例)TN10CYA
  40. ・ダメージ計算 xDM+y>=t
  41.  [ダメージ計算]を行う。成否と【HP】の減少量を表示する。
  42.  x: 6面ダイス数
  43.  y: 補正値(省略可能)
  44.  t: 防御力
  45. ・各種表
  46. 関係決定表 RELA
  47. 平時天才軍師表 PTGS
  48. 平時英傑表 PTHE
  49. スカウト表 SCOU
  50. 変調表 BDST
  51. MESSAGETEXT
  52. 1 def initialize(command)
  53. 84 super(command)
  54. 84 @d66_sort_type = D66SortType::ASC
  55. 84 @round_type = RoundType::FLOOR
  56. end
  57. 1 register_prefix('\d*TN(6|10)[ABCKSTY]*', '\d+DM')
  58. 1 def eval_game_system_specific_command(command)
  59. 84 roll_judge(command) || roll_damage(command) || roll_tables(command, self.class::TABLES)
  60. end
  61. 1 private
  62. # 行為判定
  63. 1 def roll_judge(command)
  64. 84 m = /^(\d*)TN(6|10)([ABCKSTY]*)$/.match(command)
  65. 84 else: 73 then: 11 unless m
  66. 11 return nil
  67. end
  68. # 成功となる出目
  69. 73 success_dices = [4, 5, 6, 7, 8, 9, 10]
  70. # スペシャルとなる出目
  71. 73 special_dices = [6, 10]
  72. # ファンブルとなる出目
  73. 73 fumble_dices = [1]
  74. # 有利
  75. 73 advantage = m[2] == "10"
  76. # 不調 気づかぬうちの不満
  77. 73 complaints = m[3].include?("C")
  78. # 軍師スキル 〇〇サポート
  79. 73 support = m[3].include?("S")
  80. # 英傑スキル/武人 煌めく刃
  81. 73 blade = m[3].include?("B")
  82. # 英傑スキル/武人 必殺の剣
  83. 73 killer = m[3].include?("K")
  84. # 英傑スキル/武人 二刀流
  85. 73 twin = m[3].include?("T")
  86. # 英傑スキル/カリスマ 御身のためならば
  87. 73 you = m[3].include?("Y")
  88. # 英傑スキル/弓取り 愛用の弓
  89. # 英傑スキル/英傑汎用 凄腕エージェント
  90. 73 agent = m[3].include?("A")
  91. # 二刀流の適用時
  92. 73 else: 64 if twin
  93. then: 9 # 成功となる出目に2を追加
  94. 9 success_dices.push(2)
  95. end
  96. # 〇〇サポート、煌めく刃、愛用の弓、御身のためならば、凄腕エージェントいずれかの適用時
  97. 73 else: 43 if support | blade | you | agent
  98. then: 30 # 成功となる出目に3を追加
  99. 30 success_dices.push(3)
  100. end
  101. # 煌めく刃、御身のためならば、愛用の弓、凄腕エージェントいずれかの適用時
  102. 73 else: 49 if blade | you | agent
  103. then: 24 # スペシャルとなる出目に3を追加
  104. 24 special_dices.push(3)
  105. end
  106. # 必殺の剣の適用時
  107. 73 else: 63 if killer
  108. then: 10 # スペシャルとなる出目に4,5を追加
  109. 10 special_dices.push(4)
  110. 10 special_dices.push(5)
  111. end
  112. # 気づかぬうちの不満適用時
  113. 73 else: 61 if complaints
  114. then: 12 # 成功となる出目から4を削除
  115. 12 success_dices.delete(4)
  116. end
  117. # 英傑スキル/武人 力ずく
  118. 73 times = 2 + m[1].to_i
  119. 73 then: 67 else: 6 dice_size = advantage ? 10 : 6
  120. 73 dice_list = @randomizer.roll_barabara(times, dice_size)
  121. 73 texts = []
  122. 73 is_critical = false
  123. 73 is_fumble = false
  124. 73 is_success = false
  125. # スペシャルとなる出目を含む、または、二刀流の適用時かつ同じ出目のサイコロが2つ以上出ている場合
  126. 73 else: 44 if !dice_list.intersection(special_dices).empty? | (twin & (dice_list.count != dice_list.uniq.count))
  127. then: 29 # クリティカルフラグを立てる
  128. 29 is_critical = true
  129. # スペシャルのシステムメッセージを追加
  130. 29 texts.push(translate("TensaiGunshiNiNaro.JUDGE.critical"))
  131. 29 special_effects = []
  132. # 通常時の追加効果
  133. 29 special_effects.push(translate("TensaiGunshiNiNaro.NORMAL.critical"))
  134. # 英傑スキル/武人 煌めく刃による追加効果
  135. 29 then: 4 else: 25 special_effects.push(translate("TensaiGunshiNiNaro.BLADE.critical")) if blade
  136. # 英傑スキル/カリスマ 御身のためならばによる追加効果
  137. 29 then: 4 else: 25 special_effects.push(translate("TensaiGunshiNiNaro.YOU.critical")) if you
  138. # 追加効果を結合してカッコ内に格納
  139. 29 texts.push("(#{special_effects.join('')})")
  140. end
  141. # ファンブルとなる出目を含む場合
  142. 73 else: 41 unless dice_list.intersection(fumble_dices).empty?
  143. then: 32 # ファンブルフラグを立てる
  144. 32 is_fumble = true
  145. # ファンブルのシステムメッセージを追加
  146. 32 texts.push(translate("TensaiGunshiNiNaro.JUDGE.fumble"))
  147. # ファンブルの追加効果をカッコ内に格納
  148. 32 texts.push("(#{translate('TensaiGunshiNiNaro.NORMAL.fumble')})")
  149. end
  150. 73 if dice_list.intersection(success_dices).empty?
  151. # 成功となる出目を含まない場合
  152. then: 23 # 失敗の汎用メッセージを追加
  153. 23 texts.push(translate("failure"))
  154. else
  155. # 成功となる出目を含む場合
  156. else: 50 # 成功フラグを立てる
  157. 50 is_success = true
  158. # 成功の汎用メッセージを追加
  159. 50 texts.push(translate("success"))
  160. end
  161. 73 return Result.new.tap do |r|
  162. # テキストを整形
  163. 73 r.text = "#{command} > [#{dice_list.join(',')}] > #{texts.join('')}"
  164. # 各種成否を格納
  165. 73 r.condition = is_success
  166. 73 r.critical = is_critical
  167. 73 r.fumble = is_fumble
  168. end
  169. end
  170. # ダメージ計算
  171. 1 def roll_damage(command)
  172. 11 parser = Command::Parser.new("DM", round_type: @round_type)
  173. .has_prefix_number
  174. .restrict_cmp_op_to(:>=)
  175. 11 parsed = parser.parse(command)
  176. 11 else: 6 then: 5 unless parsed
  177. 5 return nil
  178. end
  179. 6 text = ''
  180. 6 is_success = false
  181. # ダメージ計算
  182. 6 damage = @randomizer.roll_sum(parsed.prefix_number, 6) + parsed.modify_number
  183. # HP減少量計算
  184. 6 dec = damage / parsed.target_number
  185. # HP減少量の最大値は3
  186. 6 then: 2 else: 4 dec = 3 if dec > 3
  187. 6 if dec > 0
  188. # HPを減らせた場合
  189. then: 5 # 成功フラグを立てる
  190. 5 is_success = true
  191. # 成功メッセージを追加
  192. 5 text = translate("TensaiGunshiNiNaro.DAMAGE.success", damage: damage.to_s, dec: dec.to_s)
  193. else
  194. else: 1 # 失敗メッセージを追加
  195. 1 text = translate("TensaiGunshiNiNaro.DAMAGE.failure", damage: damage.to_s)
  196. end
  197. 6 return Result.new.tap do |r|
  198. # テキストを整形
  199. 6 r.text = "#{command} > #{damage} > #{text}"
  200. # 各種成否を格納
  201. 6 r.condition = is_success
  202. end
  203. end
  204. 1 class << self
  205. 1 private
  206. 1 def translate_tables(locale)
  207. {
  208. 1 "RELA" => DiceTable::D66Table.from_i18n("TensaiGunshiNiNaro.table.RELA", locale),
  209. "PTGS" => DiceTable::D66Table.from_i18n("TensaiGunshiNiNaro.table.PTGS", locale),
  210. "PTHE" => DiceTable::D66Table.from_i18n("TensaiGunshiNiNaro.table.PTHE", locale),
  211. "SCOU" => DiceTable::D66Table.from_i18n("TensaiGunshiNiNaro.table.SCOU", locale),
  212. "BDST" => DiceTable::Table.from_i18n("TensaiGunshiNiNaro.table.BDST", locale),
  213. }
  214. end
  215. end
  216. 1 TABLES = translate_tables(:ja_jp)
  217. 1 register_prefix(TABLES.keys)
  218. end
  219. end
  220. end

lib/bcdice/game_system/TheIndieHack.rb

100.0% lines covered

94.44% branches covered

41 relevant lines. 41 lines covered and 0 lines missed.
18 total branches, 17 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class TheIndieHack < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'TheIndieHack'
  7. # ゲームシステム名
  8. 1 NAME = 'The Indie Hack'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'しいんていはつく'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGETEXT
  13. ■判定 cIH+a c:CL a:能力値
  14. 例)IH: ライトダイスとダークダイスを1個ずつ振って、その結果を表示
  15. INFO_MESSAGETEXT
  16. 1 register_prefix('([+-]?\d)?IH')
  17. 1 def eval_game_system_specific_command(command)
  18. 8 resolute_action(command)
  19. end
  20. 1 private
  21. # ダイス判定
  22. # @param [String] command
  23. # @return [Result]
  24. 1 def resolute_action(command)
  25. 8 m = /([+-]?\d)?IH([+-]\d)?/.match(command)
  26. 8 else: 8 then: 0 return nil unless m
  27. 8 cl = m[1].to_i
  28. 8 abilities = m[2].to_i
  29. 8 dices = @randomizer.roll_barabara(2, 6)
  30. 8 dice_text = dices.join(",")
  31. 8 dices[0] += cl
  32. 8 dices[1] += abilities
  33. 8 dice_text2 = dices.join(",")
  34. 8 diff = dices[1] - dices[0]
  35. 8 then: 1 else: 7 side = diff < 0 ? "ライト" : "ダーク"
  36. 8 then: 1 else: 7 side = "両" if diff == 0
  37. 8 then: 3 if dice_text == dice_text2
  38. 3 output = "(IH) > #{dice_text} > #{side}#{get_success_level(diff)}"
  39. else: 5 else
  40. 5 output = "(#{m[1]}IH#{m[2]}) > [#{dice_text}] > #{dice_text2} > #{side}#{get_success_level(diff)}"
  41. end
  42. 8 then: 6 if diff > 0
  43. 6 else: 2 return Result.success(output)
  44. 2 then: 1 elsif diff < 0
  45. 1 return Result.failure(output)
  46. else: 1 else
  47. 1 return Result.new.tap do |result|
  48. 1 result.text = output
  49. end
  50. end
  51. end
  52. 1 def get_success_level(die_difference)
  53. 8 case die_difference.abs
  54. when: 1 when 0
  55. 1 return "陣営がそれぞれ確定描写を1つ追加します"
  56. when: 1 when 1
  57. 1 return "陣営が確定描写を1つ追加しますが、味方によって追加されたネガティブな確定描写を1つ受けます"
  58. when: 2 when 2
  59. 2 return "陣営が確定描写を1つ追加します"
  60. when: 1 when 3
  61. 1 return "陣営が確定描写を1つ追加し、さらに場面描写を1つ追加します"
  62. when: 1 when 4
  63. 1 return "陣営が確定描写を1つ追加し、さらにその陣営の味方ひとりも確定描写を1つ追加します"
  64. else: 2 else
  65. 2 return "陣営が確定描写を2つ追加します"
  66. end
  67. end
  68. end
  69. end
  70. end

lib/bcdice/game_system/TheOneRing2nd.rb

98.42% lines covered

95.35% branches covered

190 relevant lines. 187 lines covered and 3 lines missed.
86 total branches, 82 branches covered and 4 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class TheOneRing2nd < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "TheOneRing2nd"
  7. # ゲームシステム名
  8. 1 NAME = "一つの指輪:指輪物語TRPG2版"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "ひとつのゆひわゆひわものかたりTRPG2"
  11. 1 HELP_MESSAGE = <<~TEXT
  12. ・判定コマンド(nRG[x][@y][Az][f[0|1]][i[0|1]][w[0|1]][m[0|1]])
  13. 判定用に難易度nを指定して判定ダイスを振る。技量ダイスx、痛打判定値y、修正値zを指定可能。
  14. 技量ダイス、痛打判定値、修正値は0、または未指定(0と同じ)にできる。
  15. 痛打判定値の0、未指定は痛打判定を行わない。
  16. 修正値は判定合計値に加算され、「ガンダルフ・ルーン」や「サウロンの目」はその影響を受けない。
  17. 例1: 13RG (難易度13 技量ダイス0個)
  18. 例2: 13RG3 (難易度13 技量ダイス3個)
  19. 例3: 13RG3@10A1 (難易度13 技量ダイス3個、痛打判定10、結果に1を加算)
  20. ・表用コマンド(FD[x][f[0|1]][i[0|1]])
  21. 表用に判定ダイスを振る。修正値xが指定可能。修正値は0、あるいは未指定(0と同じ)にできる。
  22. 「ガンダルフ・ルーン」や「サウロンの目」は修正値の影響を受けず、値が10を越えることもない。
  23. 例1: FD (1d12で判定)
  24. 例2: FD1 (1d12で判定し、ダイス目に+1修正)
  25. ・コマンドオプション
  26. オプションは、判定コマンドなら4個まで、表用コマンドなら2個まで、順不同で指定可能(重複可)。
  27. f: 有利(favoured)オプション。不利と同時指定時は相殺。選択された値に◎。
  28. i: 不利(ill-favoured)オプション。有利と同時指定時は相殺。選択された値に◎。
  29. 例1: 13RG3f (難易度13 技量ダイス3個、有利)
  30. 例2: FD1f (1修正、有利)
  31. 例3: 13RG3if (難易度13 技量ダイス3個、不利、有利)
  32. ※有利/不利は相殺。
  33. 判定コマンドでは更に下記のオプションを同じ条件で指定可能。
  34. w: 疲労(weary)状態オプション。
  35. m: 絶望(miserable)状態オプション。
  36. 例1: 13RG3wf (難易度13 技量ダイス3個、疲労状態、有利)
  37. 例2: 13RG3fiwm (難易度13 技量ダイス3個、有利、不利、疲労状態、絶望状態)
  38. ※有利/不利は相殺。最大オプション数である4つを指定。
  39. ・オプションスイッチ
  40. 指定したオプションのon/offを1/0で指定可能。1はon、0はoffを表す。
  41. 複数の同じオプションへのスイッチ指定は、最後のスイッチが有効となる。
  42. 例1: 13RG3if0 (難易度13 技量ダイス3個、不利はon、有利はoff)
  43. ※ 有利指定がoffのため、相殺されず不利となる。
  44. 例2: 13RG3f1f0 (難易度13 技量ダイス3個、有利は最終的にoff)
  45. TEXT
  46. 1 register_prefix('\d+RG', 'FD')
  47. 1 SAURONS_EYE_NUMBER = 11 # サウロンの目
  48. 1 GANDALF_RUNE_NUMBER = 12 # ガンダルフ・ルーン
  49. 1 CHOICE_DIE_MARK = '◎' # 有利/不利の状態で選択されたダイスにつけるマーク
  50. # 有利/不利状態のenum
  51. 1 module FavouredState
  52. 1 NORMAL = -98 # 通常状態
  53. 1 FAVOURED = -99 # 有利状態
  54. 1 ILLFAVOURED = -100 # 不利状態
  55. end
  56. 1 def eval_game_system_specific_command(command)
  57. 130 else: 0 case command
  58. when: 99 when /^\d+RG/i
  59. 99 return rg_command_exec(command)
  60. when: 31 when /^FD/i
  61. 31 return fd_command_exec(command)
  62. end
  63. return "Error" # 到達しないはずだが、念のため
  64. end
  65. 1 private
  66. # ================ RG/FGコマンド共有メソッド等 ================#
  67. # オプションデータクラス
  68. 1 class OptionData
  69. 1 attr_reader :favoured_state, :weary, :miserable
  70. 1 def initialize(favoured_state_value: FavouredState::NORMAL, weary_condition: false, miserable_condition: false)
  71. 130 @favoured_state = favoured_state_value
  72. 130 @weary = weary_condition
  73. 130 @miserable = miserable_condition
  74. end
  75. end
  76. # 指定された修正値文字列を取得
  77. 1 def get_adjust_number_text(adjust_number)
  78. 130 adjust_number_text = ""
  79. 130 then: 13 if adjust_number > 0
  80. 13 else: 117 adjust_number_text = "+#{adjust_number}"
  81. 117 then: 9 else: 108 elsif adjust_number < 0
  82. 9 adjust_number_text = adjust_number.to_s
  83. end
  84. 130 return adjust_number_text
  85. end
  86. # 指定された状態文字列を取得
  87. 1 def get_condition_text(opts)
  88. 99 then: 51 else: 48 if opts.favoured_state == FavouredState::NORMAL && !opts.weary && !opts.miserable
  89. 51 return ""
  90. end
  91. 48 condition_text = "\n状態:"
  92. 48 then: 16 if opts.favoured_state == FavouredState::FAVOURED
  93. 16 else: 32 condition_text = "#{condition_text}有利 "
  94. 32 then: 14 else: 18 elsif opts.favoured_state == FavouredState::ILLFAVOURED
  95. 14 condition_text = "#{condition_text}不利 "
  96. end
  97. 48 then: 12 else: 36 if opts.weary
  98. 12 condition_text = "#{condition_text}疲労 "
  99. end
  100. 48 then: 12 else: 36 if opts.miserable
  101. 12 condition_text = "#{condition_text}絶望 "
  102. end
  103. 48 return condition_text.rstrip
  104. end
  105. # 指定された状態文字列を取得
  106. 1 def get_options(opt_params)
  107. 130 favoured_state_value = FavouredState::NORMAL
  108. 130 miserable_condition = false
  109. 130 weary_condition = false
  110. 130 opt_params.each do |x|
  111. 96 else: 0 case x[/[WFIM]/]
  112. when: 16 when "W"
  113. 16 weary_condition = on_option_switch?(x)
  114. when: 33 when "F"
  115. 33 favoured_state_value = get_favoured_state(on_option_switch?(x), favoured_state_value, FavouredState::FAVOURED)
  116. when: 31 when "I"
  117. 31 favoured_state_value = get_favoured_state(on_option_switch?(x), favoured_state_value, FavouredState::ILLFAVOURED)
  118. when: 16 when "M"
  119. 16 miserable_condition = on_option_switch?(x)
  120. end
  121. end
  122. 130 return OptionData.new(favoured_state_value: favoured_state_value, weary_condition: weary_condition, miserable_condition: miserable_condition)
  123. end
  124. # オプションから有利/不利状態指定を取得
  125. 1 def get_favoured_state(option_switch, before_favoured_state_value, tagert_state_type)
  126. 64 then: 53 if option_switch
  127. 53 then: 50 else: 3 if before_favoured_state_value == tagert_state_type || before_favoured_state_value == FavouredState::NORMAL
  128. 50 return tagert_state_type
  129. end
  130. 3 return FavouredState::NORMAL
  131. else: 11 else
  132. 11 then: 2 else: 9 if before_favoured_state_value == tagert_state_type
  133. 2 return FavouredState::NORMAL
  134. end
  135. end
  136. 9 return before_favoured_state_value
  137. end
  138. # オプションのON/OFFを取得
  139. 1 def on_option_switch?(opt_value)
  140. 96 then: 79 else: 17 if opt_value.length == 1 || opt_value[1..opt_value.length].to_i > 0
  141. 79 return true
  142. end
  143. 17 return false
  144. end
  145. # 技量ダイスロールを行う
  146. 1 def make_successdice_roll(success_dice_count, weary_condition)
  147. 57 dice_list = @randomizer.roll_barabara(success_dice_count, 6)
  148. 57 success_count = dice_list.count(6)
  149. 57 then: 9 if weary_condition
  150. 63 success_total_number = dice_list.reject { |i| i <= 3 }.sum
  151. else: 48 else
  152. 48 success_total_number = dice_list.sum
  153. end
  154. 57 return dice_list.to_s, success_total_number, success_count
  155. end
  156. # 判定ダイスロールを行う
  157. 1 def make_featdice_roll(favoured_state_value)
  158. 130 then: 85 else: 45 feat_dice_count = favoured_state_value == FavouredState::NORMAL ? 1 : 2
  159. 130 dice_list = @randomizer.roll_barabara(feat_dice_count, 12)
  160. 130 choice_die_number = die_choice(dice_list, favoured_state_value)
  161. 130 if feat_dice_count > 1
  162. then: 45
  163. 45 choice_index = dice_list.find_index(choice_die_number)
  164. 45 then: 25 else: 20 first_die = "#{CHOICE_DIE_MARK if choice_index == 0}#{get_specal_die_str(dice_list[0])}"
  165. 45 then: 20 else: 25 second_die = "#{CHOICE_DIE_MARK if choice_index == 1}#{get_specal_die_str(dice_list[1])}"
  166. 45 feat_result_text = "[#{first_die}, #{second_die}]"
  167. else: 85 else
  168. 85 feat_result_text = "[#{get_specal_die_str(choice_die_number)}]"
  169. end
  170. 130 return feat_result_text, choice_die_number, feat_dice_count
  171. end
  172. # 有利/不利を含めて判定ダイスの結果を取得
  173. 1 def die_choice(dice_list, favoured_state_value)
  174. 130 then: 22 if favoured_state_value == FavouredState::ILLFAVOURED
  175. 22 then: 5 if dice_list.count(SAURONS_EYE_NUMBER) >= 1
  176. 5 return SAURONS_EYE_NUMBER
  177. else: 17 else
  178. 17 return dice_list.min
  179. else: 108 end
  180. 108 then: 23 else: 85 elsif favoured_state_value == FavouredState::FAVOURED
  181. 23 then: 5 if dice_list.count(GANDALF_RUNE_NUMBER) >= 1
  182. 5 return GANDALF_RUNE_NUMBER
  183. else
  184. # ガンダルフ・ルーンが無ければサウロンの目を除いた最大値を選ぶ
  185. else: 18 # ※ どちらもサウロンの目ならサウロンの目を返す
  186. 50 then: 2 else: 16 return dice_list.count(SAURONS_EYE_NUMBER) == 2 ? SAURONS_EYE_NUMBER : dice_list.reject { |x| x == SAURONS_EYE_NUMBER }.max
  187. end
  188. end
  189. 85 return dice_list[0]
  190. end
  191. # 判定ダイスが特殊ダイス目だった場合、該当文字列に変換する
  192. 1 def get_specal_die_str(die_number)
  193. 198 then: 32 if die_number == GANDALF_RUNE_NUMBER
  194. 32 else: 166 return "ガンダルフ・ルーン"
  195. 166 then: 35 else: 131 elsif die_number == SAURONS_EYE_NUMBER
  196. 35 return "サウロンの目"
  197. end
  198. 131 return die_number
  199. end
  200. # ================ FDコマンド ================#
  201. 1 FD_ADJUST_NUMBER_INDEX = 2
  202. 1 FD_OPTION_START_INDEX = 3
  203. # FDコマンド実行
  204. 1 def fd_command_exec(command)
  205. 31 m = /\A(FD)(-?\d*)?([FI]-?\d*)?([FI]-?\d*)?$/.match(command)
  206. 31 else: 31 then: 0 unless m
  207. return ''
  208. end
  209. # コマンドパラメータ取得
  210. 31 adjust_number, opts = get_fd_params(m)
  211. # 判定ダイス処理
  212. 31 feat_result_text, feat_die_number, feat_dice_count = make_featdice_roll(opts.favoured_state)
  213. 31 result_header_text = "(#{feat_dice_count}D12"
  214. 31 return get_fd_roll_result(result_header_text, feat_result_text, feat_die_number, feat_dice_count, adjust_number)
  215. end
  216. # FDコマンド判定結果の取得
  217. 1 def get_fd_roll_result(result_header_text, feat_result_text, feat_die_number, feat_dice_count, adjust_number)
  218. # 修正値処理
  219. 31 reslt_die_number, adjust_number_text = get_fd_adjust(feat_die_number, adjust_number)
  220. 31 result_header_text = "#{result_header_text}#{adjust_number_text}) > #{feat_result_text}#{adjust_number_text}"
  221. 31 then: 23 else: 8 if adjust_number != 0 || feat_dice_count != 1
  222. 23 return "#{result_header_text} > [#{get_specal_die_str(reslt_die_number)}]"
  223. end
  224. 8 return result_header_text
  225. end
  226. # FDコマンドの修正値取得
  227. 1 def get_fd_adjust(feat_die_number, adjust_number)
  228. 31 then: 11 else: 20 if [SAURONS_EYE_NUMBER, GANDALF_RUNE_NUMBER].include?(feat_die_number)
  229. 11 return feat_die_number, get_adjust_number_text(adjust_number)
  230. end
  231. 20 res_total_num = feat_die_number + adjust_number
  232. 20 then: 1 if res_total_num > 10
  233. 1 else: 19 res_total_num = 10
  234. 19 then: 1 else: 18 elsif res_total_num < 1
  235. 1 res_total_num = 1
  236. end
  237. 20 return res_total_num, get_adjust_number_text(adjust_number)
  238. end
  239. # FDコマンドパラメータの取得
  240. 1 def get_fd_params(m)
  241. 31 adjust_number = m[FD_ADJUST_NUMBER_INDEX].to_i
  242. 31 opt_params = m[FD_OPTION_START_INDEX..m.length].compact
  243. 31 return adjust_number, get_options(opt_params)
  244. end
  245. # ================ RGコマンド ================#
  246. 1 RG_DIFFICULTY_INDEX = 1
  247. 1 RG_SUCCESS_DICE_INDEX = 3
  248. 1 RG_PIERCING_BLOWS_INDEX = 5
  249. 1 RG_ADJUST_NUMBER_INDEX = 7
  250. 1 RG_OPTION_START_INDEX = 8
  251. # RGコマンド実行
  252. 1 def rg_command_exec(command)
  253. 99 m = /\A(\d+)(RG)(\d*)(@(\d{0,2}))?(A(-?\d*))?([WFIM]-?\d*)?([WFIM]-?\d*)?([WFIM]-?\d*)?([WFIM]-?\d*)?$/.match(command)
  254. 99 else: 99 then: 0 unless m
  255. return ''
  256. end
  257. 99 success_count = 0
  258. # コマンドパラメータ取得
  259. 99 difficulty, success_dice_count, piercing_blows_number, adjust_number, opts = get_rg_params(m)
  260. # 判定ダイス処理
  261. 99 feat_result_text, feat_die_number, feat_dice_count = make_featdice_roll(opts.favoured_state)
  262. 99 then: 80 else: 19 total_dice_number = (feat_die_number != SAURONS_EYE_NUMBER ? feat_die_number : 0)
  263. 99 result_header_text = "(#{feat_dice_count}D12"
  264. 99 result_dice_text = feat_result_text
  265. # 技量ダイスが指定されているならその処理
  266. 99 then: 57 else: 42 if success_dice_count > 0
  267. 57 success_result_text, success_total_number, success_count = make_successdice_roll(success_dice_count, opts.weary)
  268. 57 total_dice_number += success_total_number
  269. 57 result_header_text = "#{result_header_text}+#{success_dice_count}D6"
  270. 57 result_dice_text = "#{result_dice_text}+#{success_result_text}"
  271. end
  272. # 修正値処理
  273. 99 total_dice_number, adjust_number_text = get_rg_adjust(total_dice_number, adjust_number)
  274. 99 result_header_text = "#{result_header_text}#{adjust_number_text}) > #{result_dice_text}#{adjust_number_text}"
  275. 99 return get_rg_roll_result(result_header_text, difficulty, feat_die_number, piercing_blows_number, total_dice_number, success_count, opts)
  276. end
  277. # 修正値と修正値テキストの取得
  278. 1 def get_rg_adjust(total_dice_number, adjust_number)
  279. 99 total_dice_number += adjust_number
  280. 99 then: 1 else: 98 total_dice_number = 0 if total_dice_number < 0
  281. 99 return total_dice_number, get_adjust_number_text(adjust_number)
  282. end
  283. # RGコマンド判定結果の取得
  284. 1 def get_rg_roll_result(result_header_text, difficulty, feat_die_number, piercing_blows_number, total_dice_number, success_count, opts)
  285. # 状態表示取得
  286. 99 condition_text = get_condition_text(opts)
  287. 99 success_count_text = "成功度 #{success_count}"
  288. # 痛打判定をブロック化
  289. 99 piercing_blows = lambda() { |feat_die_num, piercing_blows_num, res_text, cond_text|
  290. 61 then: 7 else: 54 if piercing_blows_num > 0 && feat_die_num >= piercing_blows_num && feat_die_num != SAURONS_EYE_NUMBER
  291. 7 res_text = "#{res_text} 痛打発生!"
  292. end
  293. 61 return "#{res_text}#{cond_text}"
  294. }
  295. 99 then: 14 if feat_die_number == GANDALF_RUNE_NUMBER
  296. 14 gandalf_rune_text = "#{result_header_text}:自動成功[#{success_count_text}]"
  297. 14 gandalf_rune_text = piercing_blows.call(feat_die_number, piercing_blows_number, gandalf_rune_text, condition_text)
  298. 14 then: 2 else: 12 if success_count >= 2
  299. 2 return Result.critical(gandalf_rune_text)
  300. end
  301. 12 else: 85 return Result.success(gandalf_rune_text)
  302. 85 then: 2 else: 83 elsif opts.miserable && feat_die_number == SAURONS_EYE_NUMBER
  303. 2 return Result.failure("#{result_header_text}:自動失敗#{condition_text}")
  304. end
  305. 83 result_detail_text = "難易度 #{difficulty} 達成値 #{total_dice_number}"
  306. 83 then: 36 else: 47 if difficulty > total_dice_number
  307. 36 return Result.failure("#{result_header_text} #{result_detail_text}:失敗#{condition_text}")
  308. end
  309. 47 success_text = "#{result_header_text} #{result_detail_text}:成功[#{success_count_text}]"
  310. 47 success_text = piercing_blows.call(feat_die_number, piercing_blows_number, success_text, condition_text)
  311. 47 then: 2 else: 45 if success_count >= 2
  312. 2 return Result.critical(success_text)
  313. end
  314. 45 return Result.success(success_text)
  315. end
  316. # RGコマンドパラメータの取得
  317. 1 def get_rg_params(m)
  318. 99 difficulty = m[RG_DIFFICULTY_INDEX].to_i
  319. 99 success_dice_count = m[RG_SUCCESS_DICE_INDEX].to_i
  320. 99 adjust_number = m[RG_ADJUST_NUMBER_INDEX].to_i
  321. 99 then: 16 else: 83 piercing_blows_number = m[RG_PIERCING_BLOWS_INDEX]&.to_i || -1 # -1は痛打判定自体を行わない
  322. 99 opt_params = m[RG_OPTION_START_INDEX..m.length].compact
  323. 99 return difficulty, success_dice_count, piercing_blows_number, adjust_number, get_options(opt_params)
  324. end
  325. end
  326. end
  327. end

lib/bcdice/game_system/TheUnofficialHollowKnightRPG.rb

94.85% lines covered

86.11% branches covered

97 relevant lines. 92 lines covered and 5 lines missed.
36 total branches, 31 branches covered and 5 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class TheUnofficialHollowKnightRPG < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'TheUnofficialHollowKnightRPG'
  7. # ゲームシステム名
  8. 1 NAME = 'The Unofficial Hollow Knight RPG'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'しあんおふいしやるほろうないとRPG'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・能力値判定 [n]AD[+b][#r][>=t]
  14.  n: 能力値。小数可。省略不可。
  15.  b: ボーナス、ペナルティダイス。省略可。
  16.  r: 追加リロールダイス数。省略可。
  17.  t: 目標値。>=含めて省略可。
  18.  成功数を判定。
  19.  例)1AD, 2.5AD, 1.5AD+1, 2AD#1, 2.5AD+2#2>=4
  20. ・イニシアチブ [n]INTI[+b][#r]
  21.  n: イニシアチブに使う能力値。省略不可。
  22. b: ボーナス、ペナルティダイス。省略可。
  23. r: 追加リロールダイス数。省略可。
  24.  振り直しを行ったうえでイニシアチブ値を計算。
  25.  例)1INTI, 2.5INTI, 1.5INTI+1, 2INTI#1, 2.5INTI+2#2
  26. INFO_MESSAGE_TEXT
  27. 1 register_prefix('(\d+\.?\d*)?AD([+-](\d+))?(#(\d+))?(>=(\d+))?', '(\d+\.?\d*)?(INTI|inti)([+-](\d+))?(#(\d+))?')
  28. 1 def initialize(command)
  29. 22 super(command)
  30. 22 @sort_barabara_dice = false # バラバラロール(Bコマンド)でソート無
  31. end
  32. 1 def eval_game_system_specific_command(command)
  33. 22 ability_roll(command) || initiative_roll(command)
  34. end
  35. 1 def number_with_sign_from_int(number)
  36. 22 then: 17 if number == 0
  37. 17 else: 5 return ""
  38. 5 then: 5 elsif number > 0
  39. 5 else: 0 return "+#{number.abs}"
  40. then: 0 elsif number < 0
  41. return "-#{number.abs}"
  42. else: 0 else
  43. return number.to_s
  44. end
  45. end
  46. 1 def number_with_reroll_from_int(number)
  47. 22 then: 15 if number == 0
  48. 15 else: 7 return ""
  49. 7 then: 7 elsif number > 0
  50. 7 return "\##{number}"
  51. else: 0 else
  52. return number.to_s
  53. end
  54. end
  55. # 能力値ロール
  56. 1 def ability_roll(command)
  57. 22 m = /^(\d+\.?\d*)?AD([+-](\d+))?(#(\d*))?(>=(\d+))?/.match(command)
  58. 22 else: 12 then: 10 unless m
  59. 10 return nil
  60. end
  61. 12 num_of_die = m[1].to_f
  62. 12 bonus = m[3].to_i
  63. 12 reroll = m[5].to_i
  64. 12 difficulty = m[7].to_i
  65. 12 then: 8 if /\.[1-9]+/ =~ num_of_die.to_s
  66. 8 dice_command = "#{num_of_die}AD#{number_with_sign_from_int(bonus)}#{number_with_reroll_from_int(reroll)}"
  67. 8 reroll += 1
  68. else: 4 else
  69. 4 dice_command = "#{num_of_die.to_i}AD#{number_with_sign_from_int(bonus)}#{number_with_reroll_from_int(reroll)}"
  70. end
  71. 12 then: 10 if difficulty == 0
  72. 10 difficulty = 5
  73. else: 2 else
  74. 2 dice_command += ">=#{difficulty}"
  75. end
  76. # 振られたダイスを入れる
  77. 12 values = @randomizer.roll_barabara(num_of_die.to_i + bonus, 6)
  78. # 成功数
  79. 37 result = values.count { |num| num >= difficulty }
  80. 12 failed_roll = num_of_die.to_i - result
  81. # ロールの結果の文字列
  82. 12 rolled_text = "[" + values.join(",") + "]"
  83. 12 reroll_values = []
  84. 12 then: 6 if reroll == 1
  85. 6 else: 6 reroll_values.push(@randomizer.roll_once(6))
  86. 6 then: 2 else: 4 elsif reroll > 1
  87. 2 reroll_values += @randomizer.roll_barabara(reroll, 6)
  88. end
  89. 22 reroll_result = reroll_values.count { |num| num >= difficulty }
  90. 12 then: 2 else: 10 if failed_roll < reroll_result
  91. 2 reroll_result = failed_roll
  92. end
  93. 12 result += reroll_result
  94. # リロールの結果の文字列をロールの結果の文字列に追加する
  95. 12 else: 4 then: 8 unless reroll_values.empty?
  96. 8 rolled_text += " Reroll [" + reroll_values.join(",") + "]"
  97. end
  98. # 結果
  99. 12 return "(#{dice_command}) > #{rolled_text} > #{result}成功"
  100. end
  101. # イニシアチブロール
  102. 1 def initiative_roll(command)
  103. 10 m = /^(\d+\.?\d*)?(INTI|inti)([+-](\d+))?(#(\d+))?/.match(command)
  104. 10 else: 10 then: 0 unless m
  105. return nil
  106. end
  107. 10 grace = m[1].to_f
  108. 10 bonus = m[3].to_i
  109. 10 reroll = m[6].to_i
  110. 10 then: 8 if /\.[1-9]+/ =~ grace.to_s
  111. 8 dice_command = "(#{grace}INTI#{number_with_sign_from_int(bonus)}#{number_with_reroll_from_int(reroll)})"
  112. 8 reroll += 1
  113. else: 2 else
  114. 2 dice_command = "(#{grace.to_i}INTI#{number_with_sign_from_int(bonus)}#{number_with_reroll_from_int(reroll)})"
  115. end
  116. 10 values = @randomizer.roll_barabara(grace + bonus, 6)
  117. 10 revalue = []
  118. 10 else: 2 then: 8 unless reroll == 0
  119. 8 revalue = @randomizer.roll_barabara(reroll, 6)
  120. end
  121. 10 revalue = revalue.sort
  122. 10 result = 0
  123. 10 res_text = "["
  124. 10 values.each do |value|
  125. 21 then: 4 if revalue.empty? # リロールがなければ
  126. 4 res_text += value.to_s
  127. 4 result += value
  128. else: 17 else # リロールがあったら
  129. 17 is_min = false
  130. 17 index = -1
  131. 17 revalue.each do |re|
  132. 28 index += 1
  133. 28 else: 6 then: 22 next unless re > value # リロールしたダイス最小値か
  134. 6 res_text += "#{value}<<#{re}"
  135. 6 result += re
  136. 6 revalue.delete_at(index)
  137. 6 is_min = true
  138. 6 break
  139. end
  140. 17 else: 6 then: 11 unless is_min # 最小値でなかったら
  141. 11 res_text += value.to_s
  142. 11 result += value
  143. end
  144. end
  145. 21 res_text += ","
  146. end
  147. 10 res_text = res_text.chop
  148. 10 res_text += "]"
  149. 10 return "#{dice_command} > #{res_text} > #{result}"
  150. end
  151. end
  152. end
  153. end

lib/bcdice/game_system/TherapieSein.rb

100.0% lines covered

85.71% branches covered

40 relevant lines. 40 lines covered and 0 lines missed.
14 total branches, 12 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class TherapieSein < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'TherapieSein'
  7. # ゲームシステム名
  8. 1 NAME = 'セラフィザイン'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'せらふいさいん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・一般判定:TS[n][±m][@t]  []内のコマンドは省略可能。クリティカル無。
  14. ・戦闘判定:OP[n][±m][@t]  []内のコマンドは省略可能。クリティカル有。
  15. 「n」で能力値修正などを指定。
  16. 「±m」で達成値への修正値を追加指定。+5+1-3のように、複数指定も可能です。
  17. 「@t」で目標値を指定。省略時は達成値のみ表示、指定時は判定の正否を追加表示。
  18. 【書式例】
  19. ・TS → ダイスの合計値を達成値として表示。
  20. ・TS4 → ダイス合計+4を達成値表示。
  21. ・TS4-1 → ダイス合計+4-1(計+3)を達成値表示。
  22. ・TS2+1@10 → ダイス合計+2+1(計+3)の達成値と、判定の成否を表示。
  23. ・OP4+3+1 → ダイス合計+4+3+1(計+8)を達成値&クリティカル表示。
  24. ・OP3@12 → ダイス合計+3の達成値&クリティカル、判定の成否を表示。
  25. MESSAGETEXT
  26. 1 register_prefix('TS', 'OP')
  27. 1 def eval_game_system_specific_command(command)
  28. output =
  29. 12 else: 0 case command.upcase
  30. when: 12 when /(TS|OP)(\d+)?(([+-]\d+)*)(@(\d+))?$/i
  31. 12 hasCritical = (Regexp.last_match(1) == "OP")
  32. 12 target = (Regexp.last_match(6) || 0).to_i
  33. 12 modify = (Regexp.last_match(2) || 0).to_i
  34. 12 modifyAddString = Regexp.last_match(3)
  35. 12 modify_list = modifyAddString.scan(/[+-]\d+/) # 修正値を分割して配列へ
  36. 17 modify_list.each { |i| modify += i.to_i }
  37. 12 checkRoll(hasCritical, modify, target)
  38. end
  39. 12 return output
  40. end
  41. 1 def checkRoll(hasCritical, modify, target)
  42. 12 dice_list = @randomizer.roll_barabara(2, 6)
  43. 12 dice = dice_list.sum()
  44. 12 diceText = dice_list.join(",")
  45. 12 successValue = dice + modify
  46. 12 modifyText = getValueText(modify)
  47. 12 then: 6 else: 6 targetText = (target == 0 ? '' : ">=#{target}")
  48. 12 result = "(2D6#{modifyText}#{targetText})"
  49. 12 result += " > #{dice}(#{diceText})#{modifyText}"
  50. 12 then: 2 else: 10 if hasCritical && (dice == 12)
  51. 2 result += " > クリティカル!"
  52. 2 return result
  53. end
  54. 10 result += " > #{successValue}#{targetText}"
  55. 10 then: 6 else: 4 return result if target == 0
  56. 4 then: 2 if successValue >= target
  57. 2 result += " > 【成功】"
  58. else: 2 else
  59. 2 result += " > 【失敗】"
  60. end
  61. 4 return result
  62. end
  63. 1 def getValueText(value)
  64. 12 then: 3 else: 9 return "" if value == 0
  65. 9 then: 0 else: 9 return value.to_s if value < 0
  66. 9 return "\+#{value}"
  67. end
  68. end
  69. end
  70. end

lib/bcdice/game_system/TokumeiTenkousei.rb

100.0% lines covered

90.91% branches covered

42 relevant lines. 42 lines covered and 0 lines missed.
11 total branches, 10 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class TokumeiTenkousei < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'TokumeiTenkousei'
  7. # ゲームシステム名
  8. 1 NAME = '特命転攻生'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'とくめいてんこうせい'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~HELP
  13. ・判定 (xD6+y>=n)
  14.  ゾロ目での自動振り足し
  15.  1の出目に応じてEPPの獲得量を表示
  16.  目標値 "?" には未対応
  17. HELP
  18. 1 def initialize(command)
  19. 26 super(command)
  20. 26 @sort_add_dice = true
  21. end
  22. 1 register_prefix('\d+D6')
  23. 1 def eval_game_system_specific_command(command)
  24. 26 parser = Command::Parser.new(/\d+D6/, round_type: round_type)
  25. 26 cmd = parser.parse(command)
  26. 26 else: 25 then: 1 unless cmd
  27. 1 return nil
  28. end
  29. 25 times = cmd.command.to_i
  30. 25 dice_list = @randomizer.roll_barabara(times, 6).sort
  31. 25 @dice_list = [dice_list]
  32. 25 body: 4 while same_all_dice?(dice_list)
  33. 4 dice_list = @randomizer.roll_barabara(times, 6).sort
  34. 4 @dice_list.push(dice_list)
  35. end
  36. 25 dice_list_flatten = @dice_list.flatten
  37. 25 dice_total = dice_list_flatten.sum()
  38. 25 count_one = dice_list_flatten.count(1)
  39. 25 total = dice_total + cmd.modify_number
  40. result =
  41. 25 then: 25 else: 0 if cmd.cmp_op
  42. 25 then: 16 else: 9 total.send(cmd.cmp_op, cmd.target_number) ? Result.success("成功") : Result.failure("失敗")
  43. end
  44. sequence = [
  45. 25 "(#{cmd})",
  46. interim_expr(cmd, dice_total),
  47. total.to_s,
  48. result.text,
  49. epp(count_one)
  50. ].compact
  51. 25 result.text = sequence.join(" > ")
  52. 25 return result
  53. end
  54. # 出目が全て同じか
  55. 1 def same_all_dice?(dice_list)
  56. 29 dice_list.size > 1 && dice_list.uniq.size == 1
  57. end
  58. 1 def interim_expr(cmd, dice_total)
  59. 25 then: 3 else: 22 if @dice_list.flatten.size == 1 && cmd.modify_number == 0
  60. 3 return nil
  61. end
  62. 48 dice_list = @dice_list.map { |ds| "[#{ds.join(',')}]" }.join("")
  63. 22 modifier = Format.modifier(cmd.modify_number)
  64. 22 return [dice_total.to_s, dice_list, modifier].join("")
  65. end
  66. # エキストラパワーポイント獲得
  67. #
  68. # @param count_one [Integer]
  69. # @return [String, nil]
  70. 1 def epp(count_one)
  71. 25 then: 15 else: 10 if count_one > 0
  72. 15 "#{count_one * 5}EPP獲得"
  73. end
  74. end
  75. end
  76. end
  77. end

lib/bcdice/game_system/TokyoGhostResearch.rb

65.91% lines covered

20.0% branches covered

44 relevant lines. 29 lines covered and 15 lines missed.
10 total branches, 2 branches covered and 8 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class TokyoGhostResearch < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'TokyoGhostResearch'
  7. # ゲームシステム名
  8. 1 NAME = '東京ゴーストリサーチ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'とうきようこおすとりさあち'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. 判定
  14. ・タスク処理は目標値以上の値で成功となります。
  15. 1d10>={目標値}
  16. 例:目標値「5」の場合、5~0で成功
  17. 各種表
  18. ・導入表 OP
  19. ・一般トラブル表 TB
  20. MESSAGETEXT
  21. # ダイスボットで使用するコマンドを配列で列挙する
  22. 1 register_prefix(
  23. 'OP', 'TB', 'TK?'
  24. )
  25. 1 def eval_game_system_specific_command(command)
  26. output =
  27. 20 else: 0 case command.upcase
  28. when: 0 when /TK/i
  29. return getCheckResult(command)
  30. when: 10 when 'OP'
  31. 10 tgr_opening_table
  32. when: 10 when 'TB'
  33. 10 tgr_common_trouble_table
  34. end
  35. 20 return output
  36. end
  37. 1 def getCheckResult(command)
  38. output = ""
  39. diff = 0
  40. then: 0 else: 0 if /TK?<=(\d+)/i =~ command
  41. diff = Regexp.last_match(2).to_i
  42. end
  43. then: 0 else: 0 if diff > 0
  44. output += "(1D10<=#{diff})"
  45. total_n = @randomizer.roll_once(10)
  46. output += ' > ' + total_n.to_s
  47. output += ' > ' + getCheckResultText(total_n, diff)
  48. end
  49. return output
  50. end
  51. 1 def getCheckResultText(total_n, diff)
  52. then: 0 if total_n >= diff
  53. result = "成功"
  54. else: 0 else
  55. result = "失敗"
  56. end
  57. return result
  58. end
  59. # 導入表(1d10)[OP]
  60. 1 def tgr_opening_table
  61. 10 name = "導入表"
  62. table = [
  63. 10 [1, "【病休中断】体調不良または怪我で療養中だったが強制召喚された。"],
  64. [2, "【忙殺中】別の業務で忙殺中であった。"],
  65. [3, "【出張帰り】遠方での仕事から戻ったばかり。"],
  66. [4, "【休暇取り消し】休暇中だったが呼び戻された。"],
  67. [5, "【平常運転】いつもどおりの仕事中だった。"],
  68. [6, "【休暇明け】十分に休養をとったあとで、心身ともに充実している。"],
  69. [7, "【人生の岐路】人生の岐路にまさに差し掛かったところであった。"],
  70. [8, "【同窓会】かつての同級生に会い、差を実感したばかりだった。"],
  71. [9, "【転職活動中】転職を考えて求人サイトを見ているところだった。"],
  72. [10, "【サボリ中】仕事をサボっているところに呼び出しがあった。"],
  73. ]
  74. 10 return get_1d10_table_result(name, table)
  75. end
  76. # 一般トラブル表(1d10)[TB]
  77. 1 def tgr_common_trouble_table
  78. 10 name = "一般トラブル表"
  79. table = [
  80. 10 [1, "トラブルが生じたが、間一髪、危機を脱した。【ダメージなし】"],
  81. [2, "どうにかタスクを処理したが、非常に疲労してしまった。【肉体ダメージ1点】"],
  82. [3, "タスク処理の過程で負傷してしまった。【肉体ダメージ1点】"],
  83. [4, "恐怖や混乱、ストレスなどで精神の均衡を崩してしまった。【精神ダメージ1点】"],
  84. [5, "過去のトラウマなどを思い出し、気分が沈んでしまった。【精神ダメージ1点】"],
  85. [6, "自身の信用をキズつけたり、汚名を背負ってしまった。【環境ダメージ1点】"],
  86. [7, "会社や上司の不興を買ってしまった。【環境ダメージ1点】"],
  87. [8, "疲労困憊で動くこともままならない。【肉体ダメージ1点+精神ダメージ1点】"],
  88. [9, "負傷したうえ、会社に損害を与えてしまった。【肉体ダメージ1点+環境ダメージ1点】"],
  89. [10, "上司から厳しく叱責され、まずい立場になった。【精神ダメージ1点+環境ダメージ1点】"],
  90. ]
  91. 10 return get_1d10_table_result(name, table)
  92. end
  93. 1 def get_1d10_table_result(name, table)
  94. 20 dice = @randomizer.roll_once(10)
  95. 20 output = get_table_by_number(dice, table)
  96. 20 return get_table_result(name, dice, output)
  97. end
  98. 1 def get_table_result(name, dice, output)
  99. 20 return "#{name}(#{dice}) > #{output}"
  100. end
  101. end
  102. end
  103. end

lib/bcdice/game_system/TokyoNova.rb

100.0% lines covered

100.0% branches covered

7 relevant lines. 7 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class TokyoNova < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'TokyoNova'
  7. # ゲームシステム名
  8. 1 NAME = 'トーキョーN◎VA'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'とおきよおのは'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = "※このダイスボットは部屋のシステム名表示用となります。\n"
  13. end
  14. end
  15. end

lib/bcdice/game_system/Torg.rb

96.08% lines covered

80.43% branches covered

153 relevant lines. 147 lines covered and 6 lines missed.
46 total branches, 37 branches covered and 9 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Torg < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Torg'
  7. # ゲームシステム名
  8. 1 NAME = 'トーグ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'とおく'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定 (TGm)
  14.  TORG専用の判定コマンドです。
  15.  "TG(技能基本値)"でロールします。Rコマンドに読替されます。
  16.  振り足しを自動で行い、20の出目が出たときには技能無し値も並記します。
  17. ・各種表 "(表コマンド)(数値)"で振ります。
  18.  ・一般結果表 成功度出力「RTx or RESULTx」
  19.  ・威圧/威嚇 対人行為結果表「ITx or INTIMIDATEx or TESTx」
  20.  ・挑発/トリック 対人行為結果表「TTx or TAUNTx or TRICKx or CTx」
  21.  ・間合い 対人行為結果表「MTx or MANEUVERx」
  22.  ・オーズ(一般人)ダメージ 「ODTx or ORDSx or ODAMAGEx」
  23.  ・ポシビリティー能力者ダメージ「DTx or DAMAGEx」
  24.  ・ボーナス表「BTx+y or BONUSx+y or TOTALx+y」 xは数値, yは技能基本値
  25. INFO_MESSAGE_TEXT
  26. 1 register_prefix('TG', '1R20', 'RT', 'Result', 'IT', 'Intimidate', 'Test', 'TT', 'Taunt', 'Trick', 'CT', 'MT', 'Maneuver', 'ODT', 'ords', 'odamage', 'DT', 'damage', 'BT', 'bonus', 'total')
  27. 1 def replace_text(string)
  28. 133 string = string.gsub(/Result/i, 'RT')
  29. 133 string = string.gsub(/(Intimidate|Test)/i, 'IT')
  30. 133 string = string.gsub(/(Taunt|Trick|CT)/i, 'TT')
  31. 133 string = string.gsub(/Maneuver/i, 'MT')
  32. 133 string = string.gsub(/(ords|odamage)/i, 'ODT')
  33. 133 string = string.gsub(/damage/i, 'DT')
  34. 133 string = string.gsub(/(bonus|total)/i, 'BT')
  35. 153 string = string.gsub(/TG(\d+)/i) { "1R20+#{Regexp.last_match(1)}" }
  36. 133 string = string.gsub(/TG/i, '1R20')
  37. 133 return string
  38. end
  39. #################### TORG ########################
  40. 1 def torg_check(string)
  41. 133 else: 20 then: 113 unless /(^|\s)S?(1R20([+-]\d+)*)(\s|$)/i =~ string
  42. 113 return nil
  43. end
  44. 20 string = Regexp.last_match(2)
  45. 20 mod = Regexp.last_match(3)
  46. 20 debug(mod)
  47. 20 then: 20 else: 0 mod = ArithmeticEvaluator.eval(mod) if mod
  48. 20 debug(mod)
  49. 20 mod = mod.to_i
  50. 20 skilled, unskilled, dice_str = torg_dice
  51. 20 sk_bonus = get_torg_bonus(skilled)
  52. 20 then: 20 if mod
  53. 20 then: 20 if mod > 0
  54. 20 output = "#{sk_bonus}[#{dice_str}]+#{mod}"
  55. else: 0 else
  56. output = "#{sk_bonus}[#{dice_str}]#{mod}"
  57. end
  58. else: 0 else
  59. output = "#{sk_bonus}[#{dice_str}]"
  60. end
  61. 20 output += " > " + (sk_bonus + mod).to_s
  62. 20 then: 3 else: 17 if skilled != unskilled
  63. 3 output += "(技能無" + (get_torg_bonus(unskilled) + mod).to_s + ")"
  64. end
  65. 20 output = "(#{string}) > #{output}"
  66. 20 return output
  67. end
  68. 1 def torg_dice
  69. 20 isSkilledCritical = true
  70. 20 isCritical = true
  71. 20 skilled = 0
  72. 20 unskilled = 0
  73. 20 dice_str = ""
  74. 20 body: 23 while isSkilledCritical
  75. 23 dice_n = @randomizer.roll_once(20)
  76. 23 skilled += dice_n
  77. 23 then: 20 else: 3 unskilled += dice_n if isCritical
  78. 23 else: 20 then: 3 dice_str += "," unless dice_str.empty?
  79. 23 dice_str += dice_n.to_s
  80. 23 then: 3 if dice_n == 20
  81. 3 else: 20 isCritical = false
  82. 20 then: 20 else: 0 elsif dice_n != 10
  83. 20 isSkilledCritical = false
  84. 20 isCritical = false
  85. end
  86. end
  87. 20 return skilled, unskilled, dice_str
  88. end
  89. 1 def eval_game_system_specific_command(command)
  90. 133 string = command.upcase
  91. 133 string = replace_text(string)
  92. 133 then: 20 else: 113 if (result = torg_check(string))
  93. 20 return result
  94. end
  95. 113 output = '1'
  96. 113 ttype = ""
  97. 113 value = 0
  98. 113 else: 113 then: 0 return nil unless /([RITMDB]T)(\d+([+-]\d+)*)/i =~ string
  99. 113 type = Regexp.last_match(1)
  100. 113 num = Regexp.last_match(2)
  101. 113 else: 0 case type
  102. when: 10 when 'RT'
  103. 10 value = ArithmeticEvaluator.eval(num)
  104. 10 output = get_torg_success_level(value)
  105. 10 ttype = '一般結果'
  106. when: 13 when 'IT'
  107. 13 value = ArithmeticEvaluator.eval(num)
  108. 13 output = get_torg_interaction_result_intimidate_test(value)
  109. 13 ttype = '威圧/威嚇'
  110. when: 12 when 'TT'
  111. 12 value = ArithmeticEvaluator.eval(num)
  112. 12 output = get_torg_interaction_result_taunt_trick(value)
  113. 12 ttype = '挑発/トリック'
  114. when: 13 when 'MT'
  115. 13 value = ArithmeticEvaluator.eval(num)
  116. 13 output = get_torg_interaction_result_maneuver(value)
  117. 13 ttype = '間合い'
  118. when: 29 when 'DT'
  119. 29 value = ArithmeticEvaluator.eval(num)
  120. 29 then: 15 if string =~ /ODT/i
  121. 15 output = get_torg_damage_ords(value)
  122. 15 ttype = 'オーズダメージ'
  123. else: 14 else
  124. 14 output = get_torg_damage_posibility(value)
  125. 14 ttype = 'ポシビリティ能力者ダメージ'
  126. end
  127. when: 36 when 'BT'
  128. 36 output, value = get_torg_bonus_text(num)
  129. 36 ttype = 'ボーナス'
  130. end
  131. 113 then: 113 else: 0 if ttype != ''
  132. 113 output = "#{ttype}表[#{value}] > #{output}"
  133. end
  134. 113 return output
  135. end
  136. # 一般結果表 成功度
  137. 1 def get_torg_success_level(value)
  138. success_table = [
  139. 10 [0, "ぎりぎり"],
  140. [1, "ふつう"],
  141. [3, "まあよい"],
  142. [7, "かなりよい"],
  143. [12, "すごい"]
  144. ]
  145. 10 return get_torg_table_result(value, success_table)
  146. end
  147. # 対人行為結果表
  148. # 威圧/威嚇(intimidate/Test)
  149. 1 def get_torg_interaction_result_intimidate_test(value)
  150. interaction_results_table = [
  151. 11 [0, "技能なし"],
  152. [5, "萎縮"],
  153. [10, "逆転負け"],
  154. [15, "モラル崩壊"],
  155. [17, "プレイヤーズコール"]
  156. ]
  157. 11 return get_torg_table_result(value, interaction_results_table)
  158. end
  159. # 挑発/トリック(Taunt/Trick)
  160. 1 def get_torg_interaction_result_taunt_trick(value)
  161. interaction_results_table = [
  162. 10 [0, "技能なし"],
  163. [5, "萎縮"],
  164. [10, "逆転負け"],
  165. [15, "高揚/逆転負け"],
  166. [17, "プレイヤーズコール"]
  167. ]
  168. 10 return get_torg_table_result(value, interaction_results_table)
  169. end
  170. # 間合い(maneuver)
  171. 1 def get_torg_interaction_result_maneuver(value)
  172. interaction_results_table = [
  173. 10 [0, "技能なし"],
  174. [5, "疲労"],
  175. [10, "萎縮/疲労"],
  176. [15, "逆転負け/疲労"],
  177. [17, "プレイヤーズコール"]
  178. ]
  179. 10 return get_torg_table_result(value, interaction_results_table)
  180. end
  181. 1 def get_torg_table_result(value, table)
  182. 123 output = '1'
  183. 123 table.each do |item|
  184. 1001 item_index = item[0]
  185. 1001 then: 77 else: 924 if item_index > value
  186. 77 break
  187. end
  188. 924 output = item[1]
  189. end
  190. 123 return output
  191. end
  192. # オーズダメージチャート
  193. 1 def get_torg_damage_ords(value)
  194. damage_table_ords = [
  195. 10 [0, "1"],
  196. [1, "O1"],
  197. [2, "K1"],
  198. [3, "O2"],
  199. [4, "O3"],
  200. [5, "K3"],
  201. [6, "転倒 K/O4"],
  202. [7, "転倒 K/O5"],
  203. [8, "1レベル負傷 K/O7"],
  204. [9, "1レベル負傷 K/O9"],
  205. [10, "1レベル負傷 K/O10"],
  206. [11, "2レベル負傷 K/O11"],
  207. [12, "2レベル負傷 KO12"],
  208. [13, "3レベル負傷 KO13"],
  209. [14, "3レベル負傷 KO14"],
  210. [15, "4レベル負傷 KO15"]
  211. ]
  212. 10 return get_torg_damage(value,
  213. 4,
  214. "レベル負傷 KO15",
  215. damage_table_ords)
  216. end
  217. # ポシビリティー能力者ダメージチャート
  218. 1 def get_torg_damage_posibility(value)
  219. damage_table_posibility = [
  220. 10 [0, "1"],
  221. [1, "1"],
  222. [2, "O1"],
  223. [3, "K2"],
  224. [4, "2"],
  225. [5, "O2"],
  226. [6, "転倒 O2"],
  227. [7, "転倒 K2"],
  228. [8, "転倒 K2"],
  229. [9, "1レベル負傷 K3"],
  230. [10, "1レベル負傷 K4"],
  231. [11, "1レベル負傷 O4"],
  232. [12, "1レベル負傷 K5"],
  233. [13, "2レベル負傷 O4"],
  234. [14, "2レベル負傷 KO5"],
  235. [15, "3レベル負傷 KO5"]
  236. ]
  237. 10 return get_torg_damage(value,
  238. 3,
  239. "レベル負傷 KO5",
  240. damage_table_posibility)
  241. end
  242. 1 def get_torg_damage(value, maxDamage, maxDamageString, damage_table)
  243. 20 then: 0 else: 20 if value < 0
  244. return '1'
  245. end
  246. 20 table_max_value = damage_table.length - 1
  247. 20 then: 14 else: 6 if value <= table_max_value
  248. 14 return get_torg_table_result(value, damage_table)
  249. end
  250. 6 over_kill_damage = ((value - table_max_value) / 2).to_i
  251. 6 return "" + (over_kill_damage + maxDamage).to_s + maxDamageString
  252. end
  253. 1 def get_torg_bonus_text(num)
  254. 36 val_arr = num.split(/\+/)
  255. 36 value = val_arr.shift.to_i
  256. 36 mod = ArithmeticEvaluator.eval(val_arr.join('+'))
  257. 36 resultValue = get_torg_bonus(value)
  258. 36 debug('TORG BT resultValue', resultValue)
  259. 36 debug('TORG BT mod', mod)
  260. 36 then: 26 if mod == 0
  261. 26 output = resultValue.to_s
  262. else: 10 else
  263. 10 output = getTorgBonusOutputTextWhenModDefined(value, resultValue, mod)
  264. 10 value = "#{value}+#{mod}"
  265. end
  266. 36 return output, value
  267. end
  268. 1 def getTorgBonusOutputTextWhenModDefined(value, resultValue, mod)
  269. 10 debug('getTorgBonusOutputTextWhenModDefined value, mod', value, mod)
  270. 10 then: 10 if mod > 0
  271. 10 return "#{resultValue}[#{value}]+#{mod} > #{resultValue + mod}"
  272. else: 0 else
  273. debug('resultValue', resultValue)
  274. debug('mod', mod)
  275. return "#{resultValue}[#{value}]#{mod} > #{resultValue + mod}"
  276. end
  277. end
  278. 1 def get_torg_bonus(value)
  279. bonus_table = [
  280. 59 [1, -12],
  281. [2, -10],
  282. [3, -8],
  283. [5, -5],
  284. [7, -2],
  285. [9, -1],
  286. [11, 0],
  287. [13, 1],
  288. [15, 2],
  289. [16, 3],
  290. [17, 4],
  291. [18, 5],
  292. [19, 6],
  293. [20, 7]
  294. ]
  295. 59 bonus = get_torg_table_result(value, bonus_table)
  296. 59 then: 30 else: 29 if value > 20
  297. 30 over_value_bonus = ((value - 21) / 5).to_i + 1
  298. 30 bonus += over_value_bonus
  299. end
  300. 59 return bonus
  301. end
  302. end
  303. end
  304. end

lib/bcdice/game_system/Torg1_5.rb

91.67% lines covered

75.0% branches covered

36 relevant lines. 33 lines covered and 3 lines missed.
4 total branches, 3 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/game_system/Torg'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Torg1_5 < Torg
  6. # ゲームシステムの識別子
  7. 1 ID = 'Torg1.5'
  8. # ゲームシステム名
  9. 1 NAME = 'トーグ1.5版'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'とおく1.5'
  12. 1 register_prefix(Torg.prefixes)
  13. # 一般結果表 成功度
  14. 1 def get_torg_success_level(value)
  15. success_table = [
  16. [0, "ぎりぎり"],
  17. [1, "ふつう"],
  18. [3, "まあよい"],
  19. [7, "かなりよい"],
  20. [12, "すごい"]
  21. ]
  22. return get_torg_table_result(value, success_table)
  23. end
  24. # 対人行為結果表
  25. # 威圧/威嚇(intimidate/Test)
  26. 1 def get_torg_interaction_result_intimidate_test(value)
  27. interaction_results_table = [
  28. 2 [0, "萎縮"],
  29. [5, "技能なし"],
  30. [10, "逆転負け"],
  31. [15, "モラル崩壊"],
  32. [17, "プレイヤーズコール"]
  33. ]
  34. 2 return get_torg_table_result(value, interaction_results_table)
  35. end
  36. # 挑発/トリック(Taunt/Trick)
  37. 1 def get_torg_interaction_result_taunt_trick(value)
  38. interaction_results_table = [
  39. 2 [0, "萎縮"],
  40. [5, "技能なし"],
  41. [10, "逆転負け"],
  42. [15, "高揚/逆転負け"],
  43. [17, "プレイヤーズコール"]
  44. ]
  45. 2 return get_torg_table_result(value, interaction_results_table)
  46. end
  47. # 間合い(maneuver)
  48. 1 def get_torg_interaction_result_maneuver(value)
  49. interaction_results_table = [
  50. 3 [0, "疲労"],
  51. [5, "萎縮"],
  52. [10, "技能なし"],
  53. [15, "逆転負け/疲労"],
  54. [17, "プレイヤーズコール"]
  55. ]
  56. 3 return get_torg_table_result(value, interaction_results_table)
  57. end
  58. # オーズダメージチャート
  59. 1 def get_torg_damage_ords(value)
  60. damage_table_ords = [
  61. 5 [0, "1"],
  62. [1, "O1"],
  63. [2, "K1"],
  64. [3, "O2"],
  65. [4, "K2"],
  66. [5, "転倒 O3"],
  67. [6, "転倒 K3"],
  68. [7, "転倒 K/O4"],
  69. [8, "1レベル負傷 KO4"],
  70. [9, "1レベル負傷 K/O5"],
  71. [10, "1レベル負傷 KO5"],
  72. [11, "2レベル負傷 K/O6"],
  73. [12, "2レベル負傷 KO6"],
  74. [13, "3レベル負傷 K/O7"],
  75. [14, "3レベル負傷 KO7"],
  76. [15, "4レベル負傷 KO8"]
  77. ]
  78. 5 return get_torg_damage(value, 4, 8, damage_table_ords)
  79. end
  80. # ポシビリティー能力者ダメージチャート
  81. 1 def get_torg_damage_posibility(value)
  82. damage_table_posibility = [
  83. 4 [0, "1"],
  84. [1, "1"],
  85. [2, "O1"],
  86. [3, "K1"],
  87. [4, "2"],
  88. [5, "O2"],
  89. [6, "転倒 K2"],
  90. [7, "転倒 O3"],
  91. [8, "転倒 K3"],
  92. [9, "転倒 K/O3"],
  93. [10, "1レベル負傷 K/O4"],
  94. [11, "1レベル負傷 K/O4"],
  95. [12, "1レベル負傷 KO4"],
  96. [13, "2レベル負傷 K/O5"],
  97. [14, "2レベル負傷 KO5"],
  98. [15, "3レベル負傷 KO5"]
  99. ]
  100. 4 return get_torg_damage(value, 3, 5, damage_table_posibility)
  101. end
  102. 1 def get_torg_damage(value, max_damage, max_shock, damage_table)
  103. 9 then: 0 else: 9 if value < 0
  104. return '1'
  105. end
  106. 9 table_max_value = damage_table.length - 1
  107. 9 then: 2 else: 7 if value <= table_max_value
  108. 2 return get_torg_table_result(value, damage_table)
  109. end
  110. 7 over_kill_value = ((value - table_max_value) / 2).to_i
  111. 7 over_kill_damage = max_damage + over_kill_value * 1
  112. 7 over_kill_shock = max_shock + over_kill_value * 1
  113. 7 return "#{over_kill_damage}レベル負傷 KO#{over_kill_shock}"
  114. end
  115. end
  116. end
  117. end

lib/bcdice/game_system/TorgEternity.rb

98.37% lines covered

89.77% branches covered

246 relevant lines. 242 lines covered and 4 lines missed.
88 total branches, 79 branches covered and 9 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class TorgEternity < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'TorgEternity'
  7. # ゲームシステム名
  8. 1 NAME = 'トーグ エタニティ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'とおくえたにてい'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定
  14.  ・TG
  15.   "TG[m]"で1d20をロールします。[]内は省略可能。
  16.   mは技能基本値を入れて下さい。Rコマンドに読替されます。
  17.   振り足しを自動で行い、20の出目が出たときには技能無し値も並記します。
  18.   (TORGダイスボットと同じ挙動をするコマンドです。ロールボーナスの読み替えのみ、Eternity版となります)
  19.  ・TE
  20.   "TE"で1d20をロールします。
  21.   振り足しを自動で行い、20の出目が出たときには技能無し値も並記します。
  22.   出目1の時には「Mishap! 自動失敗!」と出力されます。
  23.  ・UP
  24.   "UP[m]"で高揚状態のロール(通常の1d20に加え、1d20を追加で振り足し)を行います。
  25.   []内は省略可能。mは技能基本値を入れて下さい。
  26.   各ロールでの振り足しを自動で行い、20の出目が出たときには技能無し値も並記します。
  27.   一投目で出目1の時には「Mishap! 自動失敗!」と出力され、二投目は行われません。
  28.  ・POS
  29.   "POSm"で、ポシビリティ使用による1d20のロールを行います。
  30.   mはポシビリティを使用する前のロール結果を入れて下さい。
  31.   出目が10未満の場合は、10への読み替えが行われます。
  32.   また、振り足しを自動で行い、20の出目が出たときには技能無し値も並記します。
  33.  ・CPOS
  34.   "CPOSm"で、コズムポシビリティ使用による1d20のロールを行います。
  35.   mはポシビリティを使用する前のロール結果を入れて下さい。
  36.   出目が10未満の場合でも、10への読み替えが行われません。
  37.   振り足しは自動で行い、20の出目が出たときには技能無し値も並記します。
  38. ・ボーナスダメージロール
  39.  "xBD[+y]"でロールします。[]内は省略可能。
  40.  xはダメージダイス数。yはダメージ基本値 or 式を入れて下さい。
  41.  xは1以上が必要です。0だとエラーが出力されます。マイナス値はコマンドとして認識されません。
  42.  振り足し処理は自動で行われます。(振り足し発生時の目は、「5∞」と出力されます)
  43. ・各種表
  44.  "(表コマンド)(数値)"で振ります。
  45.  ・成功レベル表「RTx or RESULTx」
  46.  ・ダメージ結果表「DTx or DAMAGEx」
  47.  ・ロールボーナス表「BTx+y or BONUSx+y or TOTALx+y」 xは数値, yは技能基本値
  48. INFO_MESSAGE_TEXT
  49. 1 register_prefix('TE', 'UP', 'POS', 'CPOS', '\d+BD', 'TG', 'RT', 'Result', 'DT', 'damage', 'BT', 'bonus', 'total', '1R20')
  50. 1 def eval_game_system_specific_command(command)
  51. 104 torg_check(command) ||
  52. getRolld20DiceCommandResult(command) ||
  53. getUpRollDiceCommandResult(command) ||
  54. getPossibilityRollDiceCommandResult(command) ||
  55. getCosmPossibilityRollDiceCommandResult(command) ||
  56. getBonusDamageDiceCommandResult(command) ||
  57. getSuccessLevelDiceCommandResult(command) ||
  58. getDamageResultDiceCommandResult(command) ||
  59. getRollBonusDiceCommandResult(command)
  60. end
  61. 1 private
  62. #################### TORG 1.x ########################
  63. 1 def replace_text(string)
  64. 127 string = string.gsub(/TG(\d+)/i) { "1R20+#{Regexp.last_match(1)}" }
  65. 104 string = string.gsub(/TG/i, '1R20')
  66. 104 return string
  67. end
  68. 1 def torg_check(string)
  69. 104 string = replace_text(string)
  70. 104 m = /^1R20(([+-]\d+)*)$/i.match(string)
  71. 104 else: 25 then: 79 unless m
  72. 79 return nil
  73. end
  74. 25 mod = m[1]
  75. 25 debug(mod)
  76. 25 then: 25 else: 0 mod = mod ? Arithmetic.eval(mod, @round_type) : 0
  77. 25 debug(mod)
  78. 25 mod = mod.to_i
  79. 25 skilled, unskilled, dice_str, = torg_eternity_dice(false, false)
  80. 25 sk_bonus = get_torg_eternity_bonus(skilled)
  81. 25 then: 25 if mod
  82. 25 then: 24 if mod > 0
  83. 24 output = "#{sk_bonus}[#{dice_str}]+#{mod}"
  84. else: 1 else
  85. 1 output = "#{sk_bonus}[#{dice_str}]#{mod}"
  86. end
  87. else: 0 else
  88. output = "#{sk_bonus}[#{dice_str}]"
  89. end
  90. 25 output += " > " + (sk_bonus + mod).to_s
  91. 25 then: 3 else: 22 if skilled != unskilled
  92. 3 output += "(技能無" + (get_torg_eternity_bonus(unskilled) + mod).to_s + ")"
  93. end
  94. 25 output = "(#{string}) > #{output}"
  95. 25 return output
  96. end
  97. #################### TORG Eternity ########################
  98. # ロールコマンド (通常ロール)
  99. 1 def getRolld20DiceCommandResult(command)
  100. 79 debug("Torg Eternity Dice Roll Command ? ", command)
  101. 79 else: 11 then: 68 unless command == "TE"
  102. 68 return nil
  103. end
  104. 11 skilled, unskilled, dice_str, mishap = torg_eternity_dice(false, true)
  105. 11 then: 1 if mishap == 1
  106. 1 output = "d20ロール(通常) > 1d20[#{dice_str}] > Mishap! 絶対失敗!"
  107. else: 10 else
  108. 10 value_skilled = format("%+d", get_torg_eternity_bonus(skilled))
  109. 10 then: 6 if skilled != unskilled
  110. 6 value_unskilled = format("%+d", get_torg_eternity_bonus(unskilled))
  111. 6 output = "d20ロール(通常) > 1d20[#{dice_str}] > #{value_skilled}[#{skilled}](技能有) / #{value_unskilled}[#{unskilled}](技能無)"
  112. else: 4 else
  113. 4 output = "d20ロール(通常) > 1d20[#{dice_str}] > #{value_skilled}[#{skilled}]"
  114. end
  115. end
  116. 11 return output
  117. end
  118. # ロールコマンド (高揚ロール)
  119. 1 def getUpRollDiceCommandResult(command)
  120. 68 debug("Torg Eternity Dice Roll ( UP ) Command ? ", command)
  121. 68 m = /^UP(\d*)$/i.match(command)
  122. 68 else: 7 then: 61 unless m
  123. 61 return nil
  124. end
  125. 7 sequence = []
  126. 7 mod = m[1].to_i
  127. 7 skilled1, unskilled1, dice_str1, mishap = torg_eternity_dice(false, true)
  128. 7 then: 1 if mishap == 1
  129. sequence = [
  130. 1 "d20ロール(高揚)",
  131. "1d20[#{dice_str1}]",
  132. "Mishap! 絶対失敗!",
  133. ].compact
  134. else: 6 else
  135. 6 skilled2, unskilled2, dice_str2, = torg_eternity_dice(false, false)
  136. 6 subtotal_skilled = skilled1 + skilled2
  137. 6 subtotal_unskilled = unskilled1 + unskilled2
  138. 6 value_skilled = format("%+d", get_torg_eternity_bonus(subtotal_skilled))
  139. 6 value_unskilled = format("%+d", get_torg_eternity_bonus(subtotal_unskilled))
  140. 6 then: 3 if mod <= 0
  141. 3 then: 2 if subtotal_skilled != subtotal_unskilled
  142. sequence = [
  143. 2 "d20ロール(高揚)",
  144. "1d20[#{dice_str1}] + 1d20[#{dice_str2}]",
  145. "#{value_skilled}[#{subtotal_skilled}](技能有) / #{value_unskilled}[#{subtotal_unskilled}](技能無)",
  146. ].compact
  147. else: 1 else
  148. sequence = [
  149. 1 "d20ロール(高揚)",
  150. "1d20[#{dice_str1}] + 1d20[#{dice_str2}]",
  151. "#{value_skilled}[#{subtotal_skilled}]",
  152. ].compact
  153. end
  154. else: 3 else
  155. 3 then: 1 if subtotal_skilled != subtotal_unskilled
  156. sequence = [
  157. 1 "d20ロール(高揚)",
  158. "1d20[#{dice_str1}] + 1d20[#{dice_str2}] + #{mod}",
  159. "#{value_skilled}[#{subtotal_skilled}]+#{mod}(技能有) / #{value_unskilled}[#{subtotal_unskilled}]+#{mod}(技能無)",
  160. 1 format("%+d", (value_skilled.to_i + mod)) + "(技能有) / " + format("%+d", (value_unskilled.to_i + mod)) + "(技能無)",
  161. ].compact
  162. else: 2 else
  163. sequence = [
  164. 2 "d20ロール(高揚)",
  165. "1d20[#{dice_str1}] + 1d20[#{dice_str2}] + #{mod}",
  166. "#{value_skilled}[#{subtotal_skilled}]+#{mod}",
  167. 2 format("%+d", (value_skilled.to_i + mod)),
  168. ].compact
  169. end
  170. end
  171. end
  172. 7 output = sequence.join(" > ")
  173. 7 return output
  174. end
  175. # ロールコマンド (ポシビリティロール)
  176. 1 def getPossibilityRollDiceCommandResult(command)
  177. 61 debug("Torg Eternity Possibility Roll Command ? ", command)
  178. 61 m = /^POS((\d+)(\+\d+)?)$/i.match(command)
  179. 61 else: 12 then: 49 unless m
  180. 49 return nil
  181. end
  182. 12 then: 12 else: 0 output_modifier = m[1] ? Arithmetic.eval(m[1], @round_type) : 0
  183. 12 skilled, unskilled, dice_str, = torg_eternity_dice(true, false)
  184. 12 subtotal_skilled = skilled + output_modifier
  185. 12 subtotal_unskilled = unskilled + output_modifier
  186. 12 value_skilled = format("%+d", get_torg_eternity_bonus(subtotal_skilled))
  187. 12 then: 5 if subtotal_skilled != subtotal_unskilled
  188. 5 value_unskilled = format("%+d", get_torg_eternity_bonus(subtotal_unskilled))
  189. 5 output = "d20ロール(ポシビリティ) > #{output_modifier}+1d20[#{dice_str}] > #{value_skilled}[#{subtotal_skilled}](技能有) / #{value_unskilled}[#{subtotal_unskilled}](技能無)"
  190. else: 7 else
  191. 7 output = "d20ロール(ポシビリティ) > #{output_modifier}+1d20[#{dice_str}] > #{value_skilled}[#{subtotal_skilled}]"
  192. end
  193. 12 return output
  194. end
  195. # ロールコマンド (コズムポシビリティロール)
  196. 1 def getCosmPossibilityRollDiceCommandResult(command)
  197. 49 debug("Torg Eternity CosmPossibility Roll Command ? ", command)
  198. 49 m = /^CPOS((\d+)(\+\d+)?)$/i.match(command)
  199. 49 else: 3 then: 46 unless m
  200. 46 return nil
  201. end
  202. 3 then: 3 else: 0 output_modifier = m[1] ? Arithmetic.eval(m[1], @round_type) : 0
  203. 3 skilled, unskilled, dice_str, = torg_eternity_dice(false, false)
  204. 3 subtotal_skilled = skilled + output_modifier
  205. 3 subtotal_unskilled = unskilled + output_modifier
  206. 3 value_skilled = format("%+d", get_torg_eternity_bonus(subtotal_skilled))
  207. 3 then: 0 if subtotal_skilled != subtotal_unskilled
  208. value_unskilled = format("%+d", get_torg_eternity_bonus(subtotal_unskilled))
  209. output = "d20ロール(ポシビリティ) > #{output_modifier}+1d20[#{dice_str}] > #{value_skilled}[#{subtotal_skilled}](技能有) / #{value_unskilled}[#{subtotal_unskilled}](技能無)"
  210. else: 3 else
  211. 3 output = "d20ロール(ポシビリティ) > #{output_modifier}+1d20[#{dice_str}] > #{value_skilled}[#{subtotal_skilled}]"
  212. end
  213. 3 return output
  214. end
  215. # ダメージボーナスコマンド
  216. 1 def getBonusDamageDiceCommandResult(command)
  217. 46 debug("TorgEternity Bonus Damage Roll Command ? ", command)
  218. 46 m = /^(\d+)(BD)(([+-]\d+)*)$/i.match(command)
  219. 46 else: 5 then: 41 unless m
  220. 41 return nil
  221. end
  222. 5 number_bonus_die = m[1].to_i
  223. 5 value_modifier, output_modifier = get_torg_eternity_modifier(m[3])
  224. 5 then: 1 if number_bonus_die <= 0
  225. 1 output = "エラーです。xBD (x≧1) として下さい"
  226. else: 4 else
  227. 4 value_roll, output_roll = get_torg_eternity_damage_bonus_dice(number_bonus_die)
  228. 4 output_value = value_roll + value_modifier
  229. 4 output = "ボーナスダメージロール(#{number_bonus_die}BD#{output_modifier}) > #{value_roll}[#{output_roll}]#{output_modifier} > #{output_value}ダメージ"
  230. end
  231. 5 return output
  232. end
  233. # 成功レベル表コマンド
  234. 1 def getSuccessLevelDiceCommandResult(command)
  235. 41 debug("TorgEternity Success Level Table Command ? ", command)
  236. 41 m = /^(RT|Result)(-*\d+([+-]\d+)*)$/i.match(command)
  237. 41 else: 8 then: 33 unless m
  238. 33 return nil
  239. end
  240. 8 then: 8 else: 0 value = m[2] ? Arithmetic.eval(m[2], @round_type) : 0
  241. 8 debug(value)
  242. 8 then: 2 if value < 0
  243. 2 output = "Failure."
  244. else: 6 else
  245. 6 output = get_torg_eternity_success_level(value)
  246. end
  247. 8 output = "成功レベル表[#{value}] > #{output}"
  248. 8 debug(output)
  249. 8 return output
  250. end
  251. # ダメージ結果表コマンド
  252. 1 def getDamageResultDiceCommandResult(command)
  253. 33 debug("TorgEternity Damage Result Table Command ? ", command)
  254. 33 m = /^(DT|Damage)(-*\d+([+-]\d+)*)$/i.match(command)
  255. 33 else: 24 then: 9 unless m
  256. 9 return nil
  257. end
  258. 24 then: 24 else: 0 value = m[2] ? Arithmetic.eval(m[2], @round_type) : 0
  259. 24 debug(value)
  260. 24 output = get_torg_eternity_damage_result(value)
  261. 24 output = "ダメージ結果表[#{value}] > #{output}"
  262. 24 debug(output)
  263. 24 return output
  264. end
  265. # ロールボーナス表コマンド
  266. 1 def getRollBonusDiceCommandResult(command)
  267. 9 debug("TorgEternity Roll Bonus Table Command ? ", command)
  268. 9 m = /^(BT|Bonus|Total)(\d+)(([+-]\d+)*)$/i.match(command)
  269. 9 else: 5 then: 4 unless m
  270. 4 return nil
  271. end
  272. 5 value_roll = m[2].to_i
  273. 5 output_bonus = get_torg_eternity_bonus(value_roll)
  274. 5 debug(output_bonus)
  275. 5 value_modifier, output_modifier = get_torg_eternity_modifier(m[3])
  276. 5 then: 2 if value_roll <= 1
  277. 2 else: 3 output = "ロールボーナス表[#{value_roll}] > Mishap!!"
  278. 3 then: 2 elsif output_modifier.empty?
  279. 2 output = "ロールボーナス表[#{value_roll}] > #{output_bonus}"
  280. else: 1 else
  281. 1 value_result = output_bonus.to_i + value_modifier
  282. 1 debug(value_result)
  283. 1 output = "ロールボーナス表[#{value_roll}]#{output_modifier} > #{output_bonus}[#{value_roll}]#{output_modifier} > #{value_result}"
  284. end
  285. 5 debug(output)
  286. 5 return output
  287. end
  288. 1 def get_torg_eternity_table_result(value, table)
  289. 111 output = nil
  290. 111 table.each do |item|
  291. 1117 item_index = item[0]
  292. 1117 then: 63 else: 1054 if item_index > value
  293. 63 break
  294. end
  295. 1054 output = item[1]
  296. end
  297. 111 return output
  298. end
  299. # 修正式計算サブルーチン
  300. 1 def get_torg_eternity_modifier(string_modifier)
  301. 10 debug("modifier check : #{string_modifier}")
  302. 10 then: 6 if string_modifier == ''
  303. 6 value_modifier = 0
  304. 6 output_modifier = ""
  305. else: 4 else
  306. 4 then: 4 else: 0 value_modifier = string_modifier ? Arithmetic.eval(string_modifier, @round_type) : 0
  307. 4 output_modifier = format("%+d", value_modifier)
  308. end
  309. 10 debug(value_modifier)
  310. 10 debug(output_modifier)
  311. 10 return value_modifier, output_modifier
  312. end
  313. # d20ロールサブルーチン
  314. 1 def torg_eternity_dice(check_pos, check_mishap)
  315. 64 isSkilledCritical = true
  316. 64 isCritical = true
  317. 64 skilled = 0
  318. 64 unskilled = 0
  319. 64 mishap = 0
  320. 64 dice_str = ""
  321. 64 body: 107 while isSkilledCritical
  322. 107 else: 64 then: 43 dice_str += "," unless dice_str.empty?
  323. 107 dice_n = @randomizer.roll_once(20)
  324. 107 then: 12 if check_pos
  325. 12 then: 3 if dice_n < 10
  326. 3 dice_str_now = "#{dice_n}→10"
  327. 3 dice_n = 10
  328. 3 isSkilledCritical = false
  329. else: 9 else
  330. 9 dice_str_now = dice_n.to_s
  331. end
  332. 12 dice_str += dice_str_now
  333. else: 95 else
  334. 95 dice_str += dice_n.to_s
  335. end
  336. 107 skilled += dice_n
  337. 107 then: 81 else: 26 unskilled += dice_n if isCritical
  338. 107 then: 21 if dice_n == 20
  339. 21 else: 86 isCritical = false
  340. 86 then: 61 else: 25 elsif dice_n != 10
  341. 61 isSkilledCritical = false
  342. 61 isCritical = false
  343. 61 then: 2 else: 59 if check_mishap & (dice_n == 1)
  344. 2 mishap = 1
  345. end
  346. end
  347. 107 check_pos = false
  348. 107 check_mishap = false
  349. end
  350. 64 return skilled, unskilled, dice_str, mishap
  351. end
  352. # ボーナスダイスロールサブルーチン
  353. 1 def get_torg_eternity_damage_bonus_dice(number)
  354. 4 debug("bonus dice roll : #{number}")
  355. 4 value_roll = 0
  356. 4 output_roll = ""
  357. 4 then: 4 if number > 0
  358. 4 value_roll = 0
  359. 4 output_roll = ""
  360. 4 body: 16 while number > 0
  361. 16 else: 4 then: 12 output_roll = "#{output_roll}," unless output_roll.empty?
  362. 16 dice_value = @randomizer.roll_once(6)
  363. 16 dice_text = dice_value.to_s
  364. 16 then: 4 else: 12 if dice_value == 6
  365. 4 dice_value = 5
  366. 4 dice_text = "5∞"
  367. 4 number += 1
  368. end
  369. 16 value_roll += dice_value
  370. 16 output_roll = "#{output_roll}#{dice_text}"
  371. 16 debug(value_roll)
  372. 16 debug(output_roll)
  373. 16 number -= 1
  374. end
  375. else: 0 else
  376. output_roll = "0"
  377. end
  378. 4 debug(value_roll)
  379. 4 debug(output_roll)
  380. 4 return value_roll, output_roll
  381. end
  382. # 成功レベル表
  383. 1 def get_torg_eternity_success_level(value)
  384. success_table = [
  385. 6 [0, "Success - Standard."],
  386. [5, "Success - Good!"],
  387. [10, "Success - Outstanding!!"]
  388. ]
  389. 6 return get_torg_eternity_table_result(value, success_table)
  390. end
  391. # ダメージチャート
  392. 1 def get_torg_eternity_damage_result(value)
  393. damage_table = [
  394. 24 [-50, "ノーダメージ"],
  395. [-5, "1ショック"],
  396. [0, "2ショック"],
  397. [5, "1レベル負傷 + 2ショック"],
  398. [10, "2レベル負傷 + 4ショック"],
  399. [15, "3レベル負傷 + 6ショック"],
  400. [20, "4レベル負傷 + 8ショック"],
  401. [25, "5レベル負傷 + 10ショック"],
  402. [30, "6レベル負傷 + 12ショック"],
  403. [35, "7レベル負傷 + 14ショック"],
  404. [40, "8レベル負傷 + 16ショック"],
  405. [45, "9レベル負傷 + 18ショック"],
  406. [50, "10レベル負傷 + 20ショック"]
  407. ]
  408. 24 return get_torg_eternity_table_result(value, damage_table)
  409. end
  410. 1 def get_torg_eternity_bonus(value)
  411. bonus_table = [
  412. 81 [1, -10],
  413. [2, -8],
  414. [3, -6],
  415. [5, -4],
  416. [7, -2],
  417. [9, -1],
  418. [11, 0],
  419. [13, 1],
  420. [15, 2],
  421. [16, 3],
  422. [17, 4],
  423. [18, 5],
  424. [19, 6],
  425. [20, 7]
  426. ]
  427. 81 bonus = get_torg_eternity_table_result(value, bonus_table)
  428. 81 then: 39 else: 42 if value > 20
  429. 39 over_value_bonus = ((value - 21) / 5).to_i + 1
  430. 39 bonus += over_value_bonus
  431. end
  432. 81 return bonus
  433. end
  434. end
  435. end
  436. end

lib/bcdice/game_system/ToshiakiHolyGrailWar.rb

97.56% lines covered

93.75% branches covered

41 relevant lines. 40 lines covered and 1 lines missed.
16 total branches, 15 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class ToshiakiHolyGrailWar < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'ToshiakiHolyGrailWar'
  7. # ゲームシステム名
  8. 1 NAME = 'としあきの聖杯戦争TRPG'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'としあきのせいはいせんそうTRPG'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ■ 判定 (Fx+y-z@a>=t)
  14. 補正値ペナルティを自動計算してダイスの面数を決定しダイスロールを実行します。
  15. ダイス面数は2以上、10以下の範囲に制限されます。
  16. x: ステータス
  17. y: 補正値 (任意)
  18. z: マイナス補正値 (任意)
  19. a: ダイス面数の増量 (任意)
  20. t: 目標値 (任意)
  21. 例)
  22. F8+11, F8+11-5, F8+11-5@1, F8+11+9-3-2@-1, F8+11-5>=50, F8
  23. INFO_MESSAGE_TEXT
  24. 1 register_prefix('F')
  25. 1 def eval_game_system_specific_command(command)
  26. 20 roll_f(command)
  27. end
  28. 1 private
  29. 1 def roll_f(command)
  30. 20 parser = Command::Parser.new(/F(\d+)(\+\d+)*(-\d+)*/, round_type: RoundType::CEIL)
  31. .disable_modifier
  32. .enable_critical
  33. 20 cmd = parser.parse(command)
  34. 20 else: 19 then: 1 unless cmd
  35. 1 return nil
  36. end
  37. 19 m = cmd.command.match(/^F(\d+)((?:\+\d+)+)?((?:-\d+)+)?$/)
  38. 19 else: 19 then: 0 unless m
  39. return nil
  40. end
  41. 19 status = m[1].to_i
  42. 19 then: 16 else: 3 positive_modifier = m[2] ? Arithmetic.eval(m[2], RoundType::CEIL) : 0
  43. 19 then: 7 else: 12 negative_modifier = m[3] ? Arithmetic.eval(m[3], RoundType::CEIL) : 0
  44. 19 side_bonus = cmd.critical || 0
  45. 19 times = [status + positive_modifier + negative_modifier, 0].max
  46. 19 sides = (6 - positive_modifier_penalty(positive_modifier) + negative_modifier_bonus(negative_modifier) + side_bonus).clamp(2, 10)
  47. 19 list = @randomizer.roll_barabara(times, sides)
  48. 19 total = list.sum()
  49. result =
  50. 19 then: 17 if cmd.cmp_op.nil?
  51. 17 else: 2 Result.new
  52. 2 then: 1 elsif total.send(cmd.cmp_op, cmd.target_number)
  53. 1 Result.success("成功")
  54. else: 1 else
  55. 1 Result.failure("失敗")
  56. end
  57. sequence = [
  58. 19 cmd,
  59. "(#{times}D#{sides}#{cmd.cmp_op}#{cmd.target_number})",
  60. "#{total}[#{list.join(',')}]",
  61. total,
  62. result.text,
  63. ].compact
  64. 19 result.text = sequence.join(" > ")
  65. 19 return result
  66. end
  67. 1 def positive_modifier_penalty(modifier)
  68. 19 then: 11 if modifier <= 10
  69. 11 0
  70. else: 8 else
  71. 8 modifier / 10
  72. end
  73. end
  74. 1 def negative_modifier_bonus(modifier)
  75. 19 then: 5 else: 14 modifier <= -5 ? 1 : 0
  76. end
  77. end
  78. end
  79. end

lib/bcdice/game_system/TrailOfCthulhu.rb

100.0% lines covered

94.74% branches covered

56 relevant lines. 56 lines covered and 0 lines missed.
19 total branches, 18 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class TrailOfCthulhu < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'TrailOfCthulhu'
  7. # ゲームシステム名
  8. 1 NAME = 'トレイル・オブ・クトゥルー'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'とれいるおふくとうるう'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGETEXT
  13. ■技能判定 TCb[>=t] b:消費プール・ポイント t:難易度(省略可能)
  14. 例)TC2>=5:消費プール・ポイント2,難易度5で技能判定し、その結果を表示する。
  15. TC>=3: 難易度3で技能判定し、その結果を表示する。
  16. TC: 難易度指定せずに技能判定する。
  17. TC3: 消費プール・ポイント3,難易度指定せずに技能判定する。
  18. ■神話的狂気表 MMT[a,b] a,b:除外する神話的狂気(省略時は全神話的狂気を表示する)
  19. 例)MMT[1,8]: 神話的狂気のうち、1番と8番を除外してロールし、神話的狂気を決定する。
  20. MMT2,6: 神話的狂気のうち、2番と6番を除外してロールし、神話的狂気を決定する。
  21. MMT: 神話的狂気を1番から8番まで列挙する。
  22. INFO_MESSAGETEXT
  23. 1 register_prefix("TC", "MMT")
  24. 1 def initialize(command)
  25. 10 super(command)
  26. 10 @round_type = RoundType::CEIL
  27. end
  28. 1 def eval_game_system_specific_command(command)
  29. 10 resolute_action(command) ||
  30. roll_mythos_madness_table(command)
  31. end
  32. 1 private
  33. # 技能判定
  34. # @param [String] command
  35. # @return [Result]
  36. 1 def resolute_action(command)
  37. 10 m = /^TC([+\d]*)(>=(\d+))?/.match(command)
  38. 10 else: 6 then: 4 return nil unless m
  39. bonus =
  40. 6 then: 2 if m[1].empty?
  41. 2 0
  42. else: 4 else
  43. 4 Arithmetic.eval(m[1], @round_type)
  44. end
  45. 6 then: 1 else: 5 if bonus.nil?
  46. 1 return nil
  47. end
  48. 5 difficulty = m[3].to_i
  49. 5 dice = @randomizer.roll_once(6)
  50. 5 total = dice + bonus
  51. 5 return Result.new.tap do |result|
  52. 5 then: 3 if difficulty > 0
  53. 3 result.condition = (total >= difficulty)
  54. sequence = [
  55. 3 "(TC#{bonus}>=#{difficulty})",
  56. "#{dice}+#{bonus}",
  57. total.to_s,
  58. 3 then: 1 else: 2 result.success? ? "成功" : "失敗"
  59. ].compact
  60. else: 2 else
  61. sequence = [
  62. 2 "(TC#{bonus})",
  63. "#{dice}+#{bonus}",
  64. total.to_s,
  65. ].compact
  66. end
  67. 5 result.text = sequence.join(" > ")
  68. end
  69. end
  70. # 神話的狂気表
  71. 1 MITHOS_MADDNESS = [
  72. "1:強迫性障害",
  73. "2:恐怖症",
  74. "3:誇大妄想狂",
  75. "4:殺人狂",
  76. "5:恣意的記憶喪失",
  77. "6:多重人格障害",
  78. "7:偏執症",
  79. "8:妄想症",
  80. ].freeze
  81. 1 def roll_mythos_madness_table(command)
  82. 5 m = /^MMT(\[?([1-8],[1-8])\]?)?/.match(command)
  83. 5 else: 4 then: 1 return nil unless m
  84. 4 sequence = []
  85. 4 result_text = ""
  86. 4 then: 3 if m[1]
  87. 3 exclusion_number = m[2].split(',')
  88. 3 else: 3 then: 0 return nil unless exclusion_number.length == 2
  89. 3 sequence = ["(MMT[#{exclusion_number.join(',')}])"]
  90. 3 is_exclusion_number = true
  91. 3 body: 5 while is_exclusion_number
  92. 5 idx = @randomizer.roll_once(8).to_i
  93. 5 then: 3 else: 2 if idx != exclusion_number[0].to_i && idx != exclusion_number[1].to_i
  94. 3 result_text = MITHOS_MADDNESS[idx - 1]
  95. 3 is_exclusion_number = false
  96. end
  97. end
  98. else: 1 else
  99. 1 sequence = ["(MMT)"]
  100. 1 mithos_maddness_all = []
  101. 1 (1..8).each do |i|
  102. 8 mithos_maddness_all.push(MITHOS_MADDNESS[i - 1])
  103. end
  104. 1 result_text = mithos_maddness_all.join(", ")
  105. end
  106. 4 return Result.new.tap do |result|
  107. 4 sequence.push(result_text)
  108. 4 result.text = sequence.join(" > ")
  109. end
  110. end
  111. end
  112. end
  113. end

lib/bcdice/game_system/TrinitySeven.rb

100.0% lines covered

95.83% branches covered

75 relevant lines. 75 lines covered and 0 lines missed.
24 total branches, 23 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/dice_table/table"
  3. 1 require "bcdice/format"
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class TrinitySeven < Base
  7. # ゲームシステムの識別子
  8. 1 ID = 'TrinitySeven'
  9. # ゲームシステム名
  10. 1 NAME = 'トリニティセブンRPG'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = 'とりにていせふんRPG'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = <<~MESSAGETEXT
  15. クリティカルが変動した命中及び、7の出目がある場合のダメージ計算が行なえます。
  16. なお、通常の判定としても利用できます。
  17. ・発動/命中 [TR(±c*)<=(x)±(y*) 又は TR<=(x) など]*は必須ではない項目です。
  18. "TR(クリティカルの修正値*)<=(発動/命中)±(発動/命中の修正値*)"
  19. 加算減算のみ修正値も付けられます。 [修正値]は必須ではありません。
  20. 例)TR<=50 TR<=60+20 TR7<=40 TR-7<=80 TR+10<=80+20
  21. ・ダメージ計算 [(x)DM(c*)±(y*) 又は (x)DM(c*) 又は (x)DM±(y*)]*は必須ではない項目です。
  22. "(ダイス数)DM(7の出目の数*)+(修正*)"
  23. 加算減算のみ修正値も付けられます。 [7の出目の数]および[修正値]は必須ではありません。
  24. 例)6DM2+1 5DM2 4DM 3DM+3
  25. 後から7の出目に変更する場合はC(7*6+5)のように入力して計算してください。
  26. ・名前表 [TRNAME]
  27. 名字と名前を出します。PCや突然現れたNPCの名付けにどうぞ。
  28. MESSAGETEXT
  29. 1 register_prefix('\d+DM', 'TR', 'TRNAME')
  30. 1 def eval_game_system_specific_command(command) # スパゲッティなコードだけど許して!!! → 絶対に許さない。全力でリファクタリングした。
  31. 50 debug("eval_game_system_specific_command command", command)
  32. 50 roll_hit(command) ||
  33. roll_damage(command) ||
  34. roll_name(command)
  35. end
  36. 1 def roll_hit(command)
  37. 50 parser = Command::Parser.new(/TR\d*/, round_type: round_type)
  38. .restrict_cmp_op_to(:<=)
  39. 50 cmd = parser.parse(command)
  40. 50 else: 19 then: 31 return nil unless cmd
  41. 19 modify = cmd.command[2..-1].to_i + cmd.modify_number
  42. 19 critical = 7 + modify
  43. 19 target = cmd.target_number
  44. 19 total = @randomizer.roll_once(100)
  45. 19 result = get_hit_roll_result(total, target, critical)
  46. 19 cmd.command = "TR"
  47. 19 cmd.modify_number = modify
  48. 19 result.text = "(#{cmd}) > #{total} > #{result.text}"
  49. 19 debug("eval_game_system_specific_command result text", result.text)
  50. 19 result
  51. end
  52. 1 def get_hit_roll_result(total, target, critical)
  53. 19 then: 7 if total >= 96
  54. 7 else: 12 Result.fumble("ファンブル")
  55. 12 then: 8 elsif total <= critical
  56. 8 else: 4 Result.critical("クリティカル")
  57. 4 then: 2 elsif total <= target
  58. 2 Result.success("成功")
  59. else: 2 else
  60. 2 Result.failure("失敗")
  61. end
  62. end
  63. 1 def roll_damage(command)
  64. 31 parser = Command::Parser.new(/\d+DM\d*/, round_type: round_type)
  65. .restrict_cmp_op_to(nil)
  66. 31 cmd = parser.parse(command)
  67. 31 else: 25 then: 6 return nil unless cmd
  68. 25 dice_count, critical = cmd.command.split("DM", 2).map(&:to_i)
  69. 25 modify = cmd.modify_number
  70. 25 dice_list = @randomizer.roll_barabara(dice_count, 6).sort
  71. 25 dice_text = dice_list.join(",")
  72. 25 total, additionalList = get_roll_damage_result(dice_count, critical, dice_list, modify)
  73. 25 then: 8 else: 17 additionalListText = additionalList.nil? ? "" : "→[#{additionalList.join(',')}]"
  74. 25 text = "(#{cmd}) > [#{dice_text}]#{additionalListText}#{Format.modifier(modify)} > #{total}"
  75. 25 return text
  76. end
  77. 1 def get_roll_damage_result(diceCount, critical, diceList, modify)
  78. 25 then: 8 else: 17 if critical <= 0
  79. 8 total = diceList.sum() + modify
  80. 8 return total, nil
  81. end
  82. 17 restDice = diceList.clone
  83. 17 then: 0 else: 17 critical = diceCount if critical > diceCount
  84. 17 critical.times do
  85. 25 restDice.shift
  86. 25 diceList.shift
  87. 25 diceList.push(7)
  88. end
  89. 17 max = restDice.pop
  90. 17 then: 6 else: 11 max = 1 if max.nil?
  91. 17 total = max * (7**critical) + restDice.sum() + modify
  92. 17 return total, diceList
  93. end
  94. 1 def result_1d100(_total, dice_total, _cmp_op, _target)
  95. 7 then: 2 if dice_total >= 96
  96. 2 else: 5 Result.fumble("ファンブル")
  97. 5 then: 1 else: 4 elsif dice_total <= 7
  98. 1 Result.critical("クリティカル")
  99. end
  100. end
  101. 1 def roll_name(command)
  102. 6 else: 5 then: 1 unless command == "TRNAME"
  103. 1 return nil
  104. end
  105. 5 first_name = NAME1.roll(@randomizer).last_body
  106. 5 second_name = NAME2.roll(@randomizer).last_body
  107. 5 text = "#{first_name} , #{second_name}"
  108. 5 return text
  109. end
  110. 1 NAME1 = DiceTable::Table.new(
  111. "名字表",
  112. "1D100",
  113. [
  114. '春日', # 1
  115. '浅見',
  116. '風間',
  117. '神無月',
  118. '倉田',
  119. '不動',
  120. '山奈',
  121. 'シャルロック',
  122. '霧隠',
  123. '果心', # 10
  124. '今井',
  125. '長瀬',
  126. '明智',
  127. '風祭',
  128. '志貫',
  129. '一文字',
  130. '月夜野',
  131. '桜田門',
  132. '果瀬',
  133. '九十九', # 20
  134. '速水',
  135. '片桐',
  136. '葉月',
  137. 'ウィンザー',
  138. '時雨里',
  139. '神城',
  140. '水際',
  141. '一ノ江',
  142. '仁藤',
  143. '北千住', # 30
  144. '西村',
  145. '諏訪',
  146. '藤宮',
  147. '御代',
  148. '橘',
  149. '霧生',
  150. '白石',
  151. '椎名',
  152. '綾小路',
  153. '二条', # 40
  154. '光明寺',
  155. '春秋',
  156. '雪見',
  157. '刀条院',
  158. 'ランカスター',
  159. 'ハクア',
  160. 'エルタニア',
  161. 'ハーネス',
  162. 'アウグストゥス',
  163. '椎名町', # 50
  164. '鍵守',
  165. '茜ヶ崎',
  166. '鎮宮',
  167. '美柳',
  168. '鎖々塚',
  169. '櫻ノ杜',
  170. '鏡ヶ守',
  171. '輝井',
  172. '南陽',
  173. '雪乃城', # 60
  174. '六角屋',
  175. '鈴々',
  176. '東三条',
  177. '朱雀院',
  178. '青龍院',
  179. '白虎院',
  180. '玄武院',
  181. '麒麟院',
  182. 'リーシュタット',
  183. 'サンクチュアリ', # 70
  184. '六実',
  185. '須藤',
  186. 'ミレニアム',
  187. '七里',
  188. '三枝',
  189. '八殿',
  190. '藤里',
  191. '久宝',
  192. '東',
  193. '赤西', # 80
  194. '神ヶ崎',
  195. 'グランシア',
  196. 'ダークブーレード',
  197. '天光寺',
  198. '月見里',
  199. '璃宮',
  200. '藤見澤',
  201. '赤聖',
  202. '姫宮',
  203. '華ノ宮', # 90
  204. '"天才"',
  205. '"達人"',
  206. '"賢者"',
  207. '"疾風"',
  208. '"海の"',
  209. '"最強"',
  210. '"凶器"',
  211. '"灼熱"',
  212. '"人間兵器"',
  213. '"魔王"', # 100
  214. ]
  215. )
  216. 1 NAME2 = DiceTable::Table.new(
  217. "名字表",
  218. "1D100",
  219. [
  220. 'アラタ/聖', # 1
  221. 'アビィス/リリス',
  222. 'ルーグ/レヴィ',
  223. 'ラスト/アリン',
  224. 'ソラ/ユイ',
  225. 'イーリアス/アキオ',
  226. 'アカーシャ/ミラ',
  227. 'アリエス/リーゼロッテ',
  228. 'ムラサメ/シャルム',
  229. '龍貴/竜姫', # 10
  230. '英樹/春菜',
  231. '準一/湊',
  232. '急司郎/光理',
  233. '夕也/愛奈',
  234. '晴彦/アキ',
  235. '疾風/ヤシロ',
  236. 'カガリ/灯花',
  237. '次郎/優都',
  238. '春太郎/静理',
  239. 'ジン/時雨', # 20
  240. 'イオリ/伊織',
  241. 'ユウヒ/優姫',
  242. 'サツキ/翠名',
  243. 'シュライ/サクラ',
  244. 'ミナヅキ/姫乃',
  245. 'カエデ/優樹菜',
  246. 'ハル/フユ',
  247. 'ドール/瑞江',
  248. 'ニトゥレスト/キリカ',
  249. 'スカー/綾瀬', # 30
  250. '真夏/小夏',
  251. '光一/ののか',
  252. '彩/翠',
  253. 'トウカ/柊花',
  254. '命/ミコト',
  255. '司/つかさ',
  256. 'ゆとり/なごみ',
  257. '冬彦/観月',
  258. 'カレン/華恋',
  259. '清次郎/亜矢', # 40
  260. 'サード/夢子',
  261. 'ボックス/詩子',
  262. 'ヘリオス/カエデ',
  263. 'ゲート/京香',
  264. 'オンリー/パトリシア',
  265. 'ザッハーク/アーリ',
  266. 'ラスタバン/ラスティ',
  267. '桜花/燁澄',
  268. '計都/リヴィア',
  269. 'カルヴァリオ/香夜', # 50
  270. '悠人/夜々子',
  271. '太子/羽菜',
  272. '夕立/夕凪',
  273. 'アルフ/愛美',
  274. 'ファロス/灯利',
  275. 'スプートニク/詩姫',
  276. 'アーネスト/累',
  277. 'ナイン/カグヤ',
  278. 'クリア/ヒマワリ',
  279. 'ウォーカー/オリビア', # 60
  280. 'ダーク/クオン',
  281. 'ウェイヴ/凛',
  282. 'ルーン/マリエ',
  283. 'エンギ/セイギ',
  284. 'シラヌイ/ミライ',
  285. 'ブライン/キズナ',
  286. 'クロウ/カナタ',
  287. 'スレイヤー/ヒカル',
  288. 'レス/ミリアリア',
  289. 'ミフユ/サリエル', # 70
  290. '鳴央/音央',
  291. 'モンジ/理亜',
  292. 'パルデモントゥム/スナオ',
  293. 'ミシェル/詩穂',
  294. 'フレンズ/サン',
  295. 'サトリ/識',
  296. 'ロード/唯花',
  297. 'クロノス/久宝',
  298. 'フィラデルフィア/冬海',
  299. 'ティンダロス/美星', # 80
  300. '勇弥/ユーリス',
  301. 'エイト/アンジェラ',
  302. 'サタン/ルシエル',
  303. 'エース/小波',
  304. 'セージ/胡蝶',
  305. '忍/千之',
  306. '重吾/キリコ',
  307. 'マイケル/ミホシ',
  308. 'カズマ/鶴香',
  309. 'ヤマト/エリシエル', # 90
  310. '歴史上の人物の名前(信長、ジャンヌなど)',
  311. 'スポーツ選手の名前(ベッカム、沙保里など)',
  312. '学者の名前(ソクラテス、エレナなど)',
  313. 'アイドルの名前(タクヤ、聖子など)',
  314. '土地、国、町の名前(イングランド、ワシントンなど)',
  315. 'モンスターの名前(ドラゴン、ラミアなど)',
  316. '武器防具の名前(ソード、メイルなど)',
  317. '自然現象の名前(カザンハリケーンなど)',
  318. '機械の名前(洗濯機、テレビなど)',
  319. '目についた物の名前(シャーペン、メガネなど)', # 100
  320. ]
  321. )
  322. end
  323. end
  324. end

lib/bcdice/game_system/TunnelsAndTrolls.rb

96.18% lines covered

81.97% branches covered

157 relevant lines. 151 lines covered and 6 lines missed.
61 total branches, 50 branches covered and 11 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class TunnelsAndTrolls < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'TunnelsAndTrolls'
  7. # ゲームシステム名
  8. 1 NAME = 'トンネルズ&トロールズ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'とんねるすあんととろおるす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・行為判定 (nD6+x>=nLV)
  14. 失敗、成功、自動失敗の自動判定とゾロ目の振り足し経験値の自動計算を行います。
  15. SAVEの難易度を「レベル」で表記することが出来ます。
  16. 例えば「2Lv」と書くと「25」に置換されます。
  17. 判定時以外は悪意ダメージを表示します。
  18. バーサークとハイパーバーサーク用に専用コマンドが使えます。
  19. 例)2D6+1>=1Lv
  20.   (2D6+1>=20) > 7[2,5]+1 > 8 > 失敗
  21.  判定時にはゾロ目を自動で振り足します。
  22. ・バーサークとハイパーバーサーク (nBS+x or nHBS+x)
  23.  "(ダイス数)BS(修正値)"でバーサーク、"(ダイス数)HBS(修正値)"でハイパーバーサークでロールできます。
  24.  最初のダイスの読替は、個別の出目はそのままで表示。
  25.  下から2番目の出目をずらした分だけ合計にマイナス修正を追加して表示します。
  26. INFO_MESSAGE_TEXT
  27. 1 register_prefix('\d+H?BS', '\d+R6', '\d+D\d+')
  28. 1 def initialize(command)
  29. 141 super(command)
  30. 141 @sort_add_dice = true
  31. end
  32. 1 private
  33. 1 def replace_text(string)
  34. 40 then: 40 else: 0 if /BS/i =~ string
  35. 50 string = string.gsub(/(\d+)HBS([^\d\s][+\-\d]+)/i) { "#{Regexp.last_match(1)}R6#{Regexp.last_match(2)}[H]" }
  36. 50 string = string.gsub(/(\d+)HBS/i) { "#{Regexp.last_match(1)}R6[H]" }
  37. 50 string = string.gsub(/(\d+)BS([^\d\s][+\-\d]+)/i) { "#{Regexp.last_match(1)}R6#{Regexp.last_match(2)}" }
  38. 50 string = string.gsub(/(\d+)BS/i) { "#{Regexp.last_match(1)}R6" }
  39. end
  40. 40 return string
  41. end
  42. 1 def eval_game_system_specific_command(string)
  43. 141 then: 101 else: 40 if /^\d+D\d+/i.match?(string)
  44. 101 return roll_action(string)
  45. end
  46. 40 string = replace_text(string)
  47. 40 debug('tandt_berserk string', string)
  48. 40 output = "1"
  49. 40 else: 40 then: 0 return output unless (m = /(^|\s)S?((\d+)[rR]6([+\-\d]*)(\[(\w+)\])?)(\s|$)/i.match(string))
  50. 40 debug('tandt_berserk matched')
  51. 40 string = m[2]
  52. 40 dice_c = m[3].to_i
  53. 40 bonus = 0
  54. 40 then: 40 else: 0 bonus = ArithmeticEvaluator.eval(m[4]) if m[4]
  55. 40 isHyperBerserk = false
  56. 40 then: 20 else: 20 isHyperBerserk = true if m[5] && (m[6] =~ /[Hh]/)
  57. 40 dice_arr = []
  58. 40 dice_now = 0
  59. 40 dice_str = ""
  60. 40 isFirstLoop = true
  61. 40 n_max = 0
  62. 40 bonus2 = 0
  63. 40 debug('isHyperBerserk', isHyperBerserk)
  64. # 2回目以降
  65. 40 dice_arr.push(dice_c)
  66. 40 loop do
  67. 196 debug('loop dice_arr', dice_arr)
  68. 196 dice_wk = dice_arr.shift
  69. 196 debug('roll dice_wk d6', dice_wk)
  70. 196 dice_list = @randomizer.roll_barabara(dice_wk, 6).sort
  71. 196 rollTotal = dice_list.sum()
  72. 196 rollDiceMaxCount = dice_list.count(6)
  73. 196 then: 196 else: 0 if dice_wk >= 2 # ダイスが二個以上
  74. 196 dice_num = dice_list
  75. 196 diceType = 6
  76. 196 dice_face = []
  77. 196 diceType.times do |_i|
  78. 1176 dice_face.push(0)
  79. end
  80. 196 dice_num.each do |dice_o|
  81. 790 dice_face[dice_o - 1] += 1
  82. end
  83. 196 dice_face.each do |dice_o|
  84. 1176 then: 154 else: 1022 if dice_o >= 2
  85. 154 then: 126 else: 28 dice_o += 1 if isHyperBerserk
  86. 154 dice_arr.push(dice_o)
  87. end
  88. end
  89. 196 then: 2 else: 194 if isFirstLoop && dice_arr.empty?
  90. 2 min1 = 0
  91. 2 min2 = 0
  92. 2 diceType.times do |i|
  93. 12 index = diceType - i - 1
  94. 12 debug('diceType index', index)
  95. 12 then: 10 else: 2 if dice_face[index] > 0
  96. 10 min2 = min1
  97. 10 min1 = index
  98. end
  99. end
  100. 2 debug("min1, min2", min1, min2)
  101. 2 bonus2 = -(min2 - min1)
  102. 2 then: 0 else: 2 rollDiceMaxCount -= 1 if min2 == 5
  103. 2 then: 0 if isHyperBerserk
  104. dice_arr.push(3)
  105. else: 2 else
  106. 2 dice_arr.push(2)
  107. end
  108. end
  109. end
  110. 196 dice_now += rollTotal
  111. 196 then: 156 else: 40 dice_str += "][" if dice_str != ""
  112. 196 dice_str += dice_list.join(",")
  113. 196 n_max += rollDiceMaxCount
  114. 196 isFirstLoop = false
  115. 196 debug('loop last chek dice_arr', dice_arr)
  116. 196 then: 40 else: 156 break if dice_arr.empty?
  117. end
  118. 40 debug('loop breaked')
  119. 40 debug('dice_now, bonus, bonus2', dice_now, bonus, bonus2)
  120. 40 total_n = dice_now + bonus + bonus2
  121. 40 dice_str = "[#{dice_str}]"
  122. 40 output = "#{dice_now}#{dice_str}"
  123. 40 then: 2 else: 38 if bonus2 < 0
  124. 2 debug('bonus2', bonus2)
  125. 2 output += bonus2.to_s
  126. end
  127. 40 debug('bonus', bonus)
  128. 40 then: 20 if bonus > 0
  129. 20 else: 20 output += "+#{bonus}"
  130. 20 then: 0 else: 20 elsif bonus < 0
  131. output += bonus.to_s
  132. end
  133. 40 then: 40 if output =~ /[^\d\[\]]+/
  134. 40 output = "(#{string}) > #{output} > #{total_n}"
  135. else: 0 else
  136. output = "(#{string}) > #{total_n}"
  137. end
  138. 40 then: 33 else: 7 output += " > 悪意#{n_max}" if n_max > 0
  139. 40 return output
  140. end
  141. 1 def roll_action(command)
  142. 101 command = command
  143. 40 .sub(/\d+LV$/i) { |level| level.to_i * 5 + 15 }
  144. 101 parser = Command::Parser.new(/\d+D6/, round_type: round_type)
  145. .restrict_cmp_op_to(nil, :>=)
  146. .enable_question_target()
  147. 101 cmd = parser.parse(command)
  148. 101 else: 101 then: 0 unless cmd
  149. return nil
  150. end
  151. 101 times = cmd.command.to_i
  152. 101 roll_action_dice(times)
  153. 101 total = @dice_total + cmd.modify_number
  154. 101 then: 30 else: 71 target = cmd.question_target? ? "?" : cmd.target_number
  155. sequence = [
  156. 101 "(#{cmd})",
  157. interim_expr(cmd, @dice_total),
  158. total.to_s,
  159. action_result(total, @dice_total, target),
  160. additional_result(@count_6)
  161. ].compact
  162. 101 return sequence.join(" > ")
  163. end
  164. 1 def roll_action_dice(times)
  165. 101 dice_list = @randomizer.roll_barabara(times, 6).sort
  166. 101 @dice_list = [dice_list]
  167. 101 body: 23 while same_all_dice?(dice_list)
  168. 23 dice_list = @randomizer.roll_barabara(times, 6).sort
  169. 23 @dice_list.push(dice_list)
  170. end
  171. 101 dice_list_flatten = @dice_list.flatten
  172. 101 @dice_total = dice_list_flatten.sum()
  173. 101 @count_6 = dice_list_flatten.count(6)
  174. end
  175. # 出目が全て同じか
  176. 1 def same_all_dice?(dice_list)
  177. 124 dice_list.size > 1 && dice_list.uniq.size == 1
  178. end
  179. 1 def interim_expr(cmd, dice_total)
  180. 101 then: 0 else: 101 if @dice_list.flatten.size == 1 && cmd.modify_number == 0
  181. return nil
  182. end
  183. 225 dice_list = @dice_list.map { |ds| "[#{ds.join(',')}]" }.join("")
  184. 101 modifier = Format.modifier(cmd.modify_number)
  185. 101 return [dice_total.to_s, dice_list, modifier].join("")
  186. end
  187. 1 def action_result(total, dice_total, target_number)
  188. 101 then: 3 if dice_total == 3
  189. 3 else: 98 "自動失敗"
  190. 98 then: 1 elsif target_number.nil?
  191. 1 else: 97 nil
  192. 97 then: 28 elsif target_number == "?"
  193. 28 else: 69 success_level(total, dice_total)
  194. 69 then: 20 elsif total >= target_number
  195. 20 "成功 > 経験値#{experience_point(target_number, dice_total)}"
  196. else: 49 else
  197. 49 "失敗"
  198. end
  199. end
  200. 1 def success_level(total, dice_total)
  201. 28 level = (total - 15) / 5
  202. 28 then: 23 if level <= 0
  203. 23 "失敗 > 経験値#{dice_total}"
  204. else: 5 else
  205. 5 "#{level}Lv成功 > 経験値#{dice_total}"
  206. end
  207. end
  208. 1 def experience_point(target_number, dice_total)
  209. 20 ep = 1.0 * (target_number - 15) / 5 * dice_total
  210. 20 then: 18 if ep <= 0
  211. 18 else: 2 "0"
  212. 2 then: 2 elsif int?(ep)
  213. 2 ep.to_i.to_s
  214. else: 0 else
  215. format("%.1f", ep)
  216. end
  217. end
  218. 1 def int?(v)
  219. 2 v == v.to_i
  220. end
  221. 1 def additional_result(count_6)
  222. 101 then: 41 else: 60 if count_6 > 0
  223. 41 "悪意#{count_6}"
  224. end
  225. end
  226. end
  227. end
  228. end

lib/bcdice/game_system/TwilightGunsmoke.rb

98.0% lines covered

85.71% branches covered

50 relevant lines. 49 lines covered and 1 lines missed.
14 total branches, 12 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/dice_table/table'
  3. 1 require 'bcdice/dice_table/d66_range_table'
  4. 1 require 'bcdice/dice_table/d66_grid_table'
  5. 1 require 'bcdice/format'
  6. 1 module BCDice
  7. 1 module GameSystem
  8. 1 class TwilightGunsmoke < Base
  9. # ゲームシステムの識別子
  10. 1 ID = 'TwilightGunsmoke'
  11. # ゲームシステム名
  12. 1 NAME = 'トワイライトガンスモーク'
  13. # ゲームシステム名の読みがな
  14. 1 SORT_KEY = 'とわいらいとかんすもおく'
  15. # ダイスボットの使い方
  16. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  17. ・判定
  18.  ・通常判定      2D6+m>=t[c,f]
  19.   修正値m,目標値t,クリティカル値c,ファンブル値fで判定ロールを行います。
  20.   クリティカル値、ファンブル値は省略可能です。([]ごと省略できます)
  21.   自動成功、自動失敗、成功、失敗を自動表示します。
  22. ・各種表
  23.  ・邂逅表  CT
  24.  ・オープニングチャート
  25.   リアリスティック OPR|シネマティック OPC
  26.  ・エンディングチャート
  27.   リアリスティック EDR|シネマティック EDC
  28.  ・情報収集チャート
  29.   荒野 RWL|ウェブ RWB|ストリート RST|上流 RUP
  30.  ・ドロップチャート
  31.   コーポレイト DCP|バンデッド DBD|クリミナル DCR|ニンジャ DNJ
  32.   ロボ DRB|武装車輛 DBS|ターレット DTR|メルカバ DMK
  33.   ヘリ DHL|マシンライフ DML|ゾンビ DZB|ミュータント DMT
  34.   BM/飛竜科 DHR|BM/巨爪科 DKS|フィーンド DFD
  35. ・D66ダイスあり
  36. INFO_MESSAGE_TEXT
  37. 1 def initialize(command)
  38. 31 super(command)
  39. 31 @d66_sort_type = D66SortType::NO_SORT
  40. 31 @sort_add_dice = true
  41. end
  42. 1 def eval_game_system_specific_command(command)
  43. 31 then: 7 else: 24 if (ret = check_roll(command))
  44. 7 return ret
  45. end
  46. 24 return roll_tables(command, TABLES)
  47. end
  48. 1 private
  49. 1 def check_roll(command)
  50. 31 m = /^2D6([+\-\d]*)>=(\d+)(\[(\d+)?(,(\d+))?\])?$/i.match(command)
  51. 31 else: 7 then: 24 unless m
  52. 24 return nil
  53. end
  54. 7 then: 7 else: 0 modify_number = m[1] ? ArithmeticEvaluator.eval(m[1]) : 0
  55. 7 target = m[2].to_i
  56. 7 critical = (m[4] || 12).to_i
  57. 7 fumble = (m[6] || 2).to_i
  58. 7 dice_list = @randomizer.roll_barabara(2, 6).sort
  59. 7 dice_value = dice_list.sum()
  60. 7 dice_str = dice_list.join(",")
  61. 7 total = dice_value + modify_number
  62. result =
  63. 7 then: 2 if dice_value >= critical
  64. 2 else: 5 "自動成功"
  65. 5 then: 2 elsif dice_value <= fumble
  66. 2 else: 3 "自動失敗"
  67. 3 then: 2 elsif total >= target
  68. 2 "成功"
  69. else: 1 else
  70. 1 "失敗"
  71. end
  72. sequence = [
  73. 7 "(#{command})",
  74. "#{dice_value}[#{dice_str}]#{Format.modifier(modify_number)}",
  75. total.to_s,
  76. result,
  77. ]
  78. 7 return sequence.join(" > ")
  79. end
  80. # オプニング, エンディング, 情報収集チャート用のテーブル
  81. # D66を振って決定する
  82. # 1項目あたり出目3つに対応する
  83. 1 class TGTable < DiceTable::D66RangeTable
  84. # @param name [String]
  85. # @param items [Array<String>]
  86. 1 def initialize(name, items)
  87. 8 then: 0 else: 8 if items.size != RANGE.size
  88. raise UnexpectedTableSize.new(name, items.size)
  89. end
  90. 8 items_with_range = RANGE.zip(items)
  91. 8 super(name, items_with_range)
  92. end
  93. # 1項目あたり3個
  94. 1 RANGE = [11..13, 14..16, 21..23, 24..26, 31..33, 34..36, 41..43, 44..46, 51..53, 54..56, 61..63, 64..66,].freeze
  95. end
  96. TABLES = {
  97. 1 "CT" => DiceTable::D66GridTable.new(
  98. "邂逅表",
  99. [
  100. ["【関係:恩人】", "【関係:恩人】", "【関係:秘密】", "【関係:秘密】", "【関係:保護者】", "【関係:保護者】"],
  101. ["【関係:忠誠】", "【関係:忠誠】", "【関係:憎悪】", "【関係:憎悪】", "【関係:あこがれ】", "【関係:あこがれ】"],
  102. ["【関係:殺意】", "【関係:殺意】", "【関係:同志】", "【関係:同志】", "【関係:幼子】", "【関係:幼子】"],
  103. ["【関係:興味】", "【関係:興味】", "【関係:ライバル】", "【関係:ライバル】", "【関係:師匠】", "【関係:師匠】"],
  104. ["【関係:慕情】", "【関係:慕情】", "【関係:友情】", "【関係:友情】", "【関係:家族】", "【関係:家族】"],
  105. ["【関係:忘却】", "【関係:忘却】", "【関係:ビジネス】", "【関係:ビジネス】", "【関係:腐れ縁】", "【関係:腐れ縁】"],
  106. ]
  107. ),
  108. "OPR" => TGTable.new(
  109. "オープニングチャート:リアリスティック",
  110. [
  111. "おまえはめったにない休暇をエンジョイしていた。映画、デート、エステ、ドラッグ、やり方はお前の好きにしろ。",
  112. "おまえはちょうど一仕事やり終えたところだ。おまえがどれだけ上手くやったかは自由に演出してよいが、残念ながらこの仕事の報酬はゲーム的には価値を持たない。ライフスタイルの一部として扱う。",
  113. "おまえは一仕事終えてぐっすり眠っている。だがそんな時におまえを否応なく仕事の電話がたたき起こす。",
  114. "おまえは金に困っている。家賃かもしれないし、別れた配偶者からの慰謝料請求かもしれない。とにかく、このオープニングでやってくる依頼はお前にとっては渡りに船だ。なお、この金はアフタープレイの出費に含まれるためゲーム的効果を持たない。",
  115. "おまえは警察に不審尋問されている。そんな時、突然おまえが釈放されるという声がかかった。どうやら次の依頼人がわざわざおまえの身元を保証してくれたらしい。",
  116. "おまえはコネクション(任意に選択するが、困ったらライフパスの相手とせよ)と会話している。その会話の内容がどんなものかはコネクションとおまえの関係次第だ。",
  117. "おまえは家族との大切なひとときを過ごしている。もしおまえに家族というものがいないなら、かわいがっているストリートの野良犬や行きつけのバーのマスター、あるいは離婚して親権を取られた子供あたりでもいい。",
  118. "おまえはネットワークにダイブし、情報の海を思うまま経巡っている(おまえがウェットでも、ネットワークそのものは利用できることを忘れるな)。仕事の連絡があったのはそんな時だ。",
  119. "おまえはおまえの首を狙って名を上げようとする愚かなストリートギャングをひとり血祭りに上げたところだ。",
  120. "おまえは荒野をひとり旅している。ウェイストランドの自然はお前に安らぎを与えてくれるか、おまえを苦しめているかは好きにしろ、だが仕事だ。スプロールに戻る時がきた。",
  121. "おまえはごくプライベートなひとときを過ごしている。恋人との甘い一夜かもしれないし、ドラッグやアルコールの酩酊かもしれない。",
  122. "おまえは死んだ大切な人間の墓に詣でている。心の中で別れを告げたその時、依頼人から電話がかかってきた。",
  123. ]
  124. ),
  125. "OPC" => TGTable.new(
  126. "オープニングチャート:シネマティック",
  127. [
  128. "おまえは世界滅亡をたくらむテロリストのアジトを今まさに木っ端微塵に爆破したところだ。脱出したおまえに、休むヒマもなく新たな依頼がやってくる。",
  129. "おまえは久しぶりに日常を楽しんでいた……はずだった。だが、おまえの乗る飛行機/船/列車がジャックされ、おまえはテロリストを徒手空拳でどうにか倒した。疲労困憊したおまえに新しい仕事がやってくる。",
  130. "おまえはまったく無関係な別の敵に捕まって拷問されている。もっとも敵はエキストラだ。おまえは自由に脱出するまでのプロセスを演出できる。",
  131. "おまえはムショにブチこまれている。幸いデイブレイカーだとバレてはいない。だが突然釈放の声がかかった。どうやら新しい依頼人が政治的圧力をかけたらしい。",
  132. "おまえは今まさに、暴走したバイオモンスターに喰われそうになっている。こんな時に依頼というのはどんなバカだ。おまえはこのピンチをどう切り抜けたか自由に演出できる。",
  133. "おまえは夢を見ていた。夢の中でおまえはまったく別の世界の、まったく別の人生を送っている。目覚めてもそちらが現実だったような気がする。まあそれはそれとして仕事だ。",
  134. "おまえはカジノで途方もなく大勝ちをしている。目の前にチップの山が積み上がり、支配人の顔が青くなっていく。だがその時、仕事の呼び出しがかかった。残念ながらチップを換金するヒマはない(あるいは換金出来たが、オープニングの間に使い切ったとしてもいい)。",
  135. "おまえは上手くやった。ネットで、リアルスペースで、芸能界で、暗黒街で、とにかくおまえのやったことは大評判を呼び、見知らぬ男たちと女たちがおまえの名を囁き交わす。そんな時におまえに依頼が来るのは当然と言えるだろう。",
  136. "おまえはヘマをやった。ポリス、情報機関、マフィア、とにかくそんなものがおまえを追い回している。おまえに依頼がやってきたのはよりによってそんな時だ。おまえは判定なしでこの窮地を切り抜けることができる。",
  137. "おまえはアイデンティティの危機に襲われる。おまえはクローンかもしれないし、記憶を継承したドロイドなのかもしれない。おまえは死んでいてネクロモーフなのかもしれない。まあそれはそれとして仕事だ。",
  138. "おまえは目覚めると見知らぬ異性(または同性)と同じベッドの中にいた。何事だ。まるで身に覚えがない。シャワーを浴びて部屋に戻ると、相手は忽然と煙のように消えていた。呆然とするおまえの電話が鳴る・仕事らしい。その相手と仕事が関係あるのかは、GMが決定せよ。",
  139. "おまえはショッピングモールでゾンビの大群に包囲されている。おまえは判定なしでこのゾンビパラダイスから脱出できるが、その過程をGMと協力して演出すること。",
  140. ]
  141. ),
  142. "EDR" => TGTable.new(
  143. "エンディングチャート:リアリスティック",
  144. [
  145. "おまえは死んだ誰かの墓に詣でている。帰ってこないものは確かにあるのだ。",
  146. "おまえはいつもの日常の喧騒へと戻っていく。家賃の請求、弾薬の補充、日々の料理、トレイの掃除。まあそんなところだ。",
  147. "おまえは休暇をエンジョイしている。そこがホテルでもカジノでも、かかる費用はライフスタイルに含まれているものとする。",
  148. "おまえは恋人、あるいは別れた恋人との親密な時間を過ごしている。それが甘い語らいなのか、深刻な別れ話まのかは好きにするといい。",
  149. "おまえは今回の事件について、おまえのコネクションと会話している。コネクションがおまえと事件をどう思っているかは、GMと相談しろ。",
  150. "おまえは日常的な銃と硝煙の世界へ戻っていく。幸い、この荒廃世界では敵には事欠かない。違うか?",
  151. "おまえはウェイストランドに残された自然の中を歩いて行く。おまえはそこでスプロールよりも大切なものを見いだすのかもしれない。あるいはただ、冒険の一環なのかもしれない。",
  152. "おまえはドラッグ/美食/酒/タバコ/ロマンスのもたらす悦楽に心ゆくまで浸っている。おまえは立派に仕事をやりとげた。当分は動きたくない。",
  153. "おまえはトレーニングに励んでいる。ひとつの戦いは終わった。だがこの先にはさらなる戦いが待っている。そのときのために、鍛錬は必要なのだ。",
  154. "おまえは株式投資や新興宗教の教祖といった「副業」に精を出している。それによって儲かっているにせよ儲かっていないにせよ、ゲームデータとしての金には影響しない。",
  155. "おまえは新しいミッションを受けている。それがどのようなものか今決めてもいいし、次のシナリオの題材にしてもいい。",
  156. "おまえは家族と過ごしている。家族と呼べる相手がいないなら、近所の野良猫でも行きつけのバーのマスターでもいいだろう。",
  157. ]
  158. ),
  159. "EDC" => TGTable.new(
  160. "エンディングチャート:シネマティック",
  161. [
  162. "おまえは自分がアンドロイドであり、自分を人間だと思い込んでいたことを突如として思い出す。そしておまえには、おまえを追う刺客が迫っている。",
  163. "おまえはこのシナリオの記憶がまったく存在しないことを思い出す。あるいは記憶だと思っていたものは、VRで植え付けられた偽記憶だったのかもしれない。おまえが誰かを探す旅が今始まる。",
  164. "おまえは平和な日常に戻っていく。ところで画面が切り替わり、BOSSの墓が映る。墓が不気味に蠢いてシーンエンド。",
  165. "なんとめでたいことに、名前を聞いたこともない遠縁の親戚の遺産がころがりこむ。スプロールの外れた洋館で魔術の研究をしていたらしい。おまえは遺産を受け継ぐため嵐の洋館へ向かっていく。",
  166. "おまえは悪の黒幕(このシナリオの黒幕とは限らない)拳/拳銃/カタナの一撃で倒し、立ち去っていく。背後で大爆発。悪は滅んだ。",
  167. "おまえは有名になりすぎた。お前を殺すために暗黒街が、メガ・コーポが、最強の刺客軍団を送り込んでくる。無論全員エキストラだ。お前が好き放題倒したら、シーンを終了させろ。",
  168. "おまえはウェイストランドを探検し、ついに誰もたどりついたことのない秘境の都市を発見した。そこに何が眠っているのか。おまえはただひとり、都市へと向かう……!",
  169. "おまえはおまえはようやく平穏な日常に戻って来た。のんびり過ごそうとした海岸のリゾートで悲鳴が上がる。なんてことだ! ゾンビ化した巨大鮫の襲撃だ! 畜生!",
  170. "おまえはストリートの闇へ戻っていく。おまえのコネクションがおまえに囁く。「どうやらBOSSが全身をサイバーウェアでつなぎ止め、復活しておまえへの復讐を企んでいるらしいぞ」その言葉に、おまえは……。",
  171. "今やストリートの伝説になったおまえには、密かにクローンが作り出されていた。対決する本人とクローン! 激震する暗黒街! 勝つのはどちらだ! 待て、次回!",
  172. "倒したはずの宿敵(今回のBOSSとは限らない)がゾンビになって復活した。なんてしぶとい野郎だ。おまえはチェーンソーを手に立ち向かう。",
  173. "仕事を終えてねぐらに戻ろうとするおまえを光が包み込んだ。UFOのアブダクションだ。果たしておまえの運命はどうなるのか。収拾がつかなくなった場合、夢だったことにするといい。",
  174. ]
  175. ),
  176. "RWL" => TGTable.new(
  177. "情報収集チャート:荒野",
  178. [
  179. "どこまでも続く果てしない荒野と廃墟、かつてここに文明があったというのが信じられれない。あるいはあの輻輳都市が蜃気楼なのかもしれない。",
  180. "どこかのバカが仕掛けた地雷が埋まっている! 【反射】難易度12の判定を行ない、失敗すれば〈殴〉5D+総合レベルのダメージを受ける。",
  181. "まともに説明したらリプレイ一冊分になるような冒険の果て、お前は情報提供者のところにたどり着いた。【HP】を(総合レベル)D点失う。",
  182. "伝説の白いワニだ! なぜワニがこんな下水道に!? 【体力】難易度12の判定を行ない、成功すれば威信点1を得る。失敗なら、〈斬〉10Dダメージ。",
  183. "山間の峠を抜けると、素晴らしく美しい湖と草原に出た。まだこんな自然が残っていたのか。おまえの【MP】を完全に回復する。",
  184. "たどりついた村人の親切な歓待。とっておきの肉のシチューを振る舞われる。【体力】難易度12の判定を行ない、成功すれば【HP】【MP】が完全に回復。失敗なら、【HP】を5D点失う。",
  185. "フェリシア・リーの行商。おまえは購入難易度20以下のアイテムひとつを定価で購入してもよい(情報収集とは別に行なえる)。",
  186. "バイオモンスターに襲われたらしい死体を発見する。端末で照合すると賞金首らしい。おまえが倒したことにするなら、威信点2を失い、$5000を得る。",
  187. "情報は古い機械式の金庫に収められていた。【反射】難易度12の判定を行ない、成功なら次の情報収集+2(クリティカルなら+$500)。失敗なら金庫が自爆し、次の情報収集-2。",
  188. "なんてこった、ゾンビの襲撃だ! 「種別:ゾンビ」で、おまえがもっともレベルの近いエネミー1D体がおまえを襲撃する。登場難易度の12のシーンで戦闘を行なうこと。距離は2マス。",
  189. "旧時代の知識を持つ親切なロボットがおまえの手助けをしてくれた。次の情報収集に+2。",
  190. "墜落したUFOを発見する。おまえは見なかったことにしてもよいし、雑誌社に売りつけてもよい。売りつけるなら、1D66×100$を得る。",
  191. ]
  192. ),
  193. "RWB" => TGTable.new(
  194. "情報収集チャート:ウェブ",
  195. [
  196. "特に何事もない。ネットの世界はルーチンワークだ。おまえは粛々と情報を集めていく。",
  197. "まさにおまえが必要としている情報の入ったファイルが、データ流の中を漂流していく。冗談か? 【幸運】難易度12の判定を行ない、成功すれば情報収集の達成値+2。ファンブルなら、情報収集そのものも失敗する。",
  198. "コネクションのひとりからVRチャットのお誘い。どうやらまったく無関係に、ヤツは君と世間話がしたいようだ。だが、何か関連情報を知っているかもしれないぞ。【幸運】難易度12の判定を行ない、成功すれば情報収集の達成値+1。クリティカルなら、威信点にも+1。",
  199. "おまえはネットの海に果てしなく潜り続ける。無数の情報がお前を魅惑し幻惑する。お前は万能だ。だが現実の肉体はそうではない。【体力】難易度12の判定を行ない、成失敗すると3D+キャラクターレベル点のHPを失う。ファンブルならその二倍だ。",
  200. "目当ての情報に近いファイルを見つけた……。だが、それには悪質な電脳ドラッグの“お試し”データが仕込まれていた。【意志】難易度12の判定を行ない、失敗した場合、次のシーンの開始時、お前は狼狽・放心を受ける。",
  201. "「ああ、その件なら知っているよ」お前のツレのハッカーが、そのネタを知っているらしい。しかもオープンソース精神とやらで、金はいらないそうだ。情報収集の達成値+2。",
  202. "どうやらおまえが貸しを作っているライバルのハッカーが、お前の追っている事件についてのネタを握っているらしい。威信点を1点減らすなら、次の情報収集のクリティカル値を-2(下限値8)。",
  203. "高速化された論理迷路の仕掛けられたデータストアに迷い込む。これだけ厳重な防御があるということは、核心の情報が保管されている可能性が高い。【知覚】難易度12の判定を行ない、成功すれば情報収集の達成値+2。失敗なら、-2。",
  204. "目まぐるしい映像の洪水が流れて行く。ネットはいつでも広告と無縁ではいられない。お前はその中から、有用そうなデータをいくつか集めた。このシナリオ中、おまえの購入判定のクリティカル値を-1(下限値8)。",
  205. "「最高のエクスタシー。肉体を捨てたトランスヒューマンだけの、嗜好の悦楽……」VRドラッグの試供品をもらう。おまえがウェットでないなら、【MP】を3D+総合レベル点回復すること。",
  206. "おまえの個人情報がタレ流しになっていることに気付く。どこかのバカのいやがらせだ。だが、うまく処理できれば名が上がる。【理知】難易度12の判定を行ない、成功すれば威信点+1。失敗なら-1。",
  207. "どうやら目当ての情報は、まだ誰も破ったことのないデータストアに保管されているようだ。それを破ったとなれば、間違いなくおまえのハッカーとしての名は上がる。次の情報収集判定に成功した場合、威信点+1D。",
  208. ]
  209. ),
  210. "RST" => TGTable.new(
  211. "情報収集チャート:ストリート",
  212. [
  213. "特筆すべき出来事はない。降り止まない酸性雨、うつむきがちの人々、けばけばしいネオンに広告飛行船。今日はいつも通りの日常だ。",
  214. "「てめえを殺りゃあ、幹部なんだよ!」密造拳銃を手にしたチンピラの襲撃。情報源のお出ましだ。【反射】難易度12の判定に成功すれば、情報収集の達成値+2。失敗なら、〈殴〉3D+総合レベル点のダメージを受ける。",
  215. "「よぉ。あのネタ探してんだってな?」にやにや顏の悪徳警官のお出ましだ。威信点を1点消費するなら、通常の効果に加えて達成値+2(合計+4)。",
  216. "「あんたとは終わったはずよ」昔の恋人と出会う(心当たりがない。とおまえが言うなら、このイベントはスキップ。ダイス目11として扱う)。威信点を1点消費するなら、通常の効果に加えてクリティカル値-2(下限値8)。",
  217. "とにかく足で稼ぐしかなさそうだ。結局、この時代でも最後に頼れるのはそれだけだ。【体力】難易度12の判定を行ない、成功すると情報収集の達成値+2。",
  218. "なじみの店でコネクションと出会う。敵対的な関係でないなら、快く情報を伝えてくれる。情報収集の達成値+2。敵対的な関係の場合は、ダイス目21と同様の処理。",
  219. "「最近名前が売れてるらしいじゃねえか。相棒(チューマ)」知らないやつになれなれしく話しかけられた。【理知】難易度12でうまくあしらえ。成功すれば、威信点+2。",
  220. "情報収集の過程で、まったく無関係な賞金首に襲われて返り討ちに。1D×500$を得るが、時間を取られたので、情報収集の達成値-1。",
  221. "屋台から漂ってくる聞いたこともない料理の香り。実に旨そうだ。5$払って食べてもいい。その場合、【幸運】難易度12の判定を行ない、成功すると【HP】と【MP】が全回復する。失敗すると、あまりのまずさに【MP】を2D点失う。",
  222. "抗争に巻き込まれて大ケガを負った子供と知り合う。何らかの【HP】回復を施してやる(アイテムを渡すのでもいい)のなら、威信点1点を得る。",
  223. "「あんたの名前に見合った金をはずんでくれよ。チューマ」情報屋だ。総合レベルの二乗×$100を支払えば、情報収集判定の達成値に+4。",
  224. "なんてこった、ゾンビの襲撃だ! 「種別:ゾンビ」で、おまえともっともレベルの近いエネミー1D体がおまえを襲撃する。登場難易度12のシーンで戦闘を行なうこと。距離は2マス。",
  225. ]
  226. ),
  227. "RUP" => TGTable.new(
  228. "情報収集チャート:上流",
  229. [
  230. "実を伴わない会話、豪勢な食事、最新鋭の何だか分からないファッション、そしてパーティ! 世はすべて事もなし。",
  231. "きらびやかな夜会と社交界の世界では、現金の量になど価値はない。金はあって当然だからだ。問題になるのは、おまえがどれだけのセレブかだ。1Dし、その数値がおまえの現在の威信点以下なら、次の情報収集に+2。",
  232. "ポストヒューマンと呼べなくても、トランスヒューマンであるかどうか。それが上流社会に受け入れられるための最低条件だ。おまえがウェットの場合、次の情報収集に-4。",
  233. "おまえを値踏みするセレブたちの冷たい視線。おまえの生活費が$1,500未満なら、次の情報収集に-2。おまえの生活費が$4000以上なら、+2。",
  234. "「あなたの噂は聞いていますわ、ご活躍だそうね」相手はどうもおまえを知っていて、しかも好意的らしい。ありがたく話を聞く。威信点に+1。",
  235. "事件とは無関係にインサイダー情報を嗅ぎつける。手を出すなら【幸運】で難易度14。成功すれば1D×$1000(クリティカルなら$10000)を得て、失敗すれば同額(ファンブルなら$10,000)を失う。",
  236. "上流階級独特のイヤミと皮肉に満ちた会話でおまえの精神は疲弊する。現在の【MP】を半分(端数切り捨て)にせよ。こんなところ、人間の住むところじゃない。",
  237. "おまえが上流社会で一番重要なのが知り合いの数だと思い知らされる。おまえが常備化しているコネクションに「種別:上流」のキャラクターがいれば、次の情報収集に+2。",
  238. "慈善活動の募金に巻き込まれる。こういうのが大事なんだ、ヤツらの社会じゃな。おまえが[現在の威信点×$500]を支払うなら、次の情報収集に+2。",
  239. "知らないうちに流行が変わっていた。最新モードの服を急いで仕立てるなら、1D×$1,000。仕立てないなら、【幸運】難易度12の判定を行ない、失敗すればおまえの威信点を-1Dすること。",
  240. "最新の社会問題についてのウィットに富んだ会話を求められる。【理知】難易度12の判定を行なえ。成功すれば、次の情報収集に+2。失敗すれば威信点を1を失う。",
  241. "テロリストの襲撃だ! 「種別:人間」のエネミー1D体がおまえを襲撃する。登場難易度14のシーンで戦闘を行なうこと。距離は4マス。",
  242. ]
  243. ),
  244. "DCP" => DiceTable::Table.new(
  245. "ドロップチャート:コーポレイト",
  246. "2D6",
  247. [
  248. "特になし",
  249. "特になし",
  250. "特になし",
  251. "特になし",
  252. "特になし",
  253. "9㎜ピストル",
  254. "9㎜ピストル",
  255. "装飾品($200)",
  256. "装飾品($200)",
  257. "スティムパック",
  258. "スティムパック",
  259. ]
  260. ),
  261. "DBD" => DiceTable::Table.new(
  262. "ドロップチャート:バンデッド",
  263. "2D6",
  264. [
  265. "特になし",
  266. "特になし",
  267. "特になし",
  268. "特になし",
  269. "特になし",
  270. ".45口径SMG",
  271. ".45口径SMG",
  272. "戦前の缶詰($60)×4",
  273. "戦前の缶詰($60)×4",
  274. "アッパードラッグ",
  275. "アッパードラッグ",
  276. ]
  277. ),
  278. "DCR" => DiceTable::Table.new(
  279. "ドロップチャート:クリミナル",
  280. "2D6",
  281. [
  282. "特になし",
  283. "特になし",
  284. "特になし",
  285. "特になし",
  286. "特になし",
  287. "現金$1D×50",
  288. "現金$1D×50",
  289. "アルコール",
  290. "アルコール",
  291. "派手なスーツ($700)",
  292. "派手なスーツ($700)",
  293. ]
  294. ),
  295. "DNJ" => DiceTable::Table.new(
  296. "ドロップチャート:ニンジャ",
  297. "2D6",
  298. [
  299. "特になし",
  300. "特になし",
  301. "特になし",
  302. "特になし",
  303. "特になし",
  304. "シュリケン",
  305. "シュリケン",
  306. "スティムパック",
  307. "スティムパック",
  308. "スティムパック",
  309. "カタナ",
  310. ]
  311. ),
  312. "DRB" => DiceTable::Table.new(
  313. "ドロップチャート:ロボ",
  314. "2D6",
  315. [
  316. "特になし",
  317. "特になし",
  318. "特になし",
  319. "特になし",
  320. "特になし",
  321. "Eセル×2セット",
  322. "Eセル×2セット",
  323. "廃棄部品($30)×5",
  324. "廃棄部品($30)×5",
  325. "ヴォルトコーラ",
  326. "ヴォルトコーラ",
  327. ]
  328. ),
  329. "DBS" => DiceTable::Table.new(
  330. "ドロップチャート:武装車輛",
  331. "2D6",
  332. [
  333. "特になし",
  334. "特になし",
  335. "特になし",
  336. "特になし",
  337. "特になし",
  338. "現金$1D×30",
  339. "現金$1D×30",
  340. "スティムパック",
  341. "スティムパック",
  342. "5.56㎜アサルトライフル",
  343. "5.56㎜アサルトライフル",
  344. ]
  345. ),
  346. "DTR" => DiceTable::Table.new(
  347. "ドロップチャート:ターレット",
  348. "2D6",
  349. [
  350. "特になし",
  351. "特になし",
  352. "特になし",
  353. "特になし",
  354. "特になし",
  355. "7.62㎜弾×3",
  356. "7.62㎜弾×3",
  357. "廃棄部品($30)×2",
  358. "廃棄部品($30)×2",
  359. "廃棄部品($30)×2",
  360. "7.62㎜マシンガン",
  361. ]
  362. ),
  363. "DMK" => DiceTable::Table.new(
  364. "ドロップチャート:メルカバ",
  365. "2D6",
  366. [
  367. "特になし",
  368. "特になし",
  369. "特になし",
  370. "特になし",
  371. "特になし",
  372. "廃棄部品($30)×10",
  373. "廃棄部品($30)×10",
  374. "スティムパック",
  375. "スティムパック",
  376. "アッパードラッグ",
  377. "アッパードラッグ",
  378. ]
  379. ),
  380. "DHL" => DiceTable::Table.new(
  381. "ドロップチャート:ヘリ",
  382. "2D6",
  383. [
  384. "特になし",
  385. "特になし",
  386. "特になし",
  387. "特になし",
  388. "特になし",
  389. "レアメタル($100)×1D",
  390. "レアメタル($100)×1D",
  391. "スーパースティムパック",
  392. "スーパースティムパック",
  393. "アッパードラッグ×2",
  394. "アッパードラッグ×2",
  395. ]
  396. ),
  397. "DML" => DiceTable::Table.new(
  398. "ドロップチャート:マシンライフ",
  399. "2D6",
  400. [
  401. "特になし",
  402. "特になし",
  403. "特になし",
  404. "特になし",
  405. "特になし",
  406. "レアメタル($100)×1D",
  407. "レアメタル($100)×1D",
  408. "未知の金属($1,000)",
  409. "未知の金属($1,000)",
  410. "未知の金属($1,000)",
  411. "マシンライフコア($10,000)",
  412. ]
  413. ),
  414. "DZB" => DiceTable::Table.new(
  415. "ドロップチャート:ゾンビ",
  416. "2D6",
  417. [
  418. "特になし",
  419. "特になし",
  420. "特になし",
  421. "特になし",
  422. "特になし",
  423. "特になし",
  424. "ぬいぐるみ($10)",
  425. "スティムパック",
  426. "スティムパック",
  427. "装飾品($500)",
  428. "装飾品($500)",
  429. ]
  430. ),
  431. "DMT" => DiceTable::Table.new(
  432. "ドロップチャート:ミュータント",
  433. "2D6",
  434. [
  435. "特になし",
  436. "特になし",
  437. "特になし",
  438. "特になし",
  439. "特になし",
  440. "アルコール",
  441. "アルコール",
  442. "スティムパック",
  443. "スティムパック",
  444. "戦前の酒($1,500)",
  445. "戦前の酒($1,500)",
  446. ]
  447. ),
  448. "DHR" => DiceTable::Table.new(
  449. "ドロップチャート:BM/飛竜科",
  450. "2D6",
  451. [
  452. "特になし",
  453. "特になし",
  454. "特になし",
  455. "特になし",
  456. "特になし",
  457. "飛竜の鱗($500)",
  458. "飛竜の鱗($500)",
  459. "飛竜の羽根($2,000)",
  460. "飛竜の羽根($2,000)",
  461. "飛竜の羽根($2,000)",
  462. "飛竜の角($10,000)",
  463. ]
  464. ),
  465. "DKS" => DiceTable::Table.new(
  466. "ドロップチャート:BM/巨爪科",
  467. "2D6",
  468. [
  469. "特になし",
  470. "特になし",
  471. "特になし",
  472. "特になし",
  473. "特になし",
  474. "現金$200×1D",
  475. "現金$200×1D",
  476. "分厚い毛皮($3,500)",
  477. "分厚い毛皮($3,500)",
  478. "巨大な爪($7,000)",
  479. "巨大な爪($7,000)",
  480. ]
  481. ),
  482. "DFD" => DiceTable::Table.new(
  483. "ドロップチャート:フィーンド",
  484. "2D6",
  485. [
  486. "特になし",
  487. "特になし",
  488. "特になし",
  489. "特になし",
  490. "アッパードラッグ×2",
  491. "アッパードラッグ×2",
  492. "アッパードラッグ×2",
  493. "アッパードラッグD",
  494. "アッパードラッグD",
  495. "異次元の結晶($12,000)",
  496. "異次元の結晶($12,000)",
  497. ]
  498. )
  499. }.freeze
  500. 1 register_prefix('2D6', TABLES.keys)
  501. end
  502. end
  503. end

lib/bcdice/game_system/UnsungDuet.rb

100.0% lines covered

100.0% branches covered

26 relevant lines. 26 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/base"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class UnsungDuet < Base
  6. 1 ID = "UnsungDuet"
  7. 1 NAME = "アンサング・デュエット"
  8. 1 SORT_KEY = "あんさんくてゆえつと"
  9. 1 HELP_MESSAGE = <<~MESSAGETEXT
  10. ■ シフター用判定 (shifter, UDS)
  11. 1D10をダイスロールして判定を行います。
  12. 例) shifter, UDS, shifter>=5, shifter+1>=6
  13. ■ バインダー用判定 (binder, UDB)
  14. 2D6をダイスロールして判定を行います。
  15. 例) binder, UDB, binder>=5, binder+1>=6
  16. ■ 変異表
  17. ・外傷 (HIN, HInjury)
  18. ・体調の変化 (HPH, HPhysical)
  19. ・恐怖 (HFE, HFear)
  20. ・幻想化 (HFA, HFantasy)
  21. ・精神 (HMI, HMind)
  22. ・そのほか (HOT, HOther)
  23. MESSAGETEXT
  24. 1 ALIAS_1D10 = ["shifter", "UDS"].freeze
  25. 1 ALIAS_2D6 = ["binder", "UDB"].freeze
  26. 1 SHIFTER_ALIAS_REG = /^#{ALIAS_1D10.join('|')}/i.freeze
  27. 1 BINDER_ALIAS_REG = /^#{ALIAS_2D6.join('|')}/i.freeze
  28. 1 register_prefix(ALIAS_1D10, ALIAS_2D6)
  29. 1 def eval_game_system_specific_command(command)
  30. 56 command = ALIAS[command] || command
  31. 56 roll_replaced_command_if_match(command, SHIFTER_ALIAS_REG, "1D10") ||
  32. roll_replaced_command_if_match(command, BINDER_ALIAS_REG, "2D6") ||
  33. roll_tables(command, self.class::TABLES)
  34. end
  35. 1 def roll_replaced_command_if_match(command, regexp, dist)
  36. 102 then: 20 else: 82 if command.match?(regexp)
  37. 20 CommonCommand::AddDice.eval(command.sub(regexp, dist), self, @randomizer)
  38. end
  39. end
  40. 1 ALIAS = {
  41. "HInjury" => "HIN",
  42. "HPhysical" => "HPH",
  43. "HFear" => "HFE",
  44. "HFantasy" => "HFA",
  45. "HMind" => "HMI",
  46. "HOther" => "HOT",
  47. }.transform_keys(&:upcase)
  48. 1 class << self
  49. 1 private
  50. 1 def translate_tables(locale)
  51. {
  52. 2 "HIN" => DiceTable::Table.from_i18n('UnsungDuet.MutatingInjuryTable', locale),
  53. "HPH" => DiceTable::Table.from_i18n('UnsungDuet.MutatingPhysicalConditionTable', locale),
  54. "HFE" => DiceTable::Table.from_i18n('UnsungDuet.MutatingFearTable', locale),
  55. "HFA" => DiceTable::Table.from_i18n('UnsungDuet.MutatingFantasyTable', locale),
  56. "HMI" => DiceTable::Table.from_i18n('UnsungDuet.MutatingMindTable', locale),
  57. "HOT" => DiceTable::Table.from_i18n('UnsungDuet.MutatingOtherTable', locale),
  58. }.freeze
  59. end
  60. end
  61. 1 TABLES = translate_tables(:ja_jp)
  62. 1 register_prefix(ALIAS.keys, TABLES.keys)
  63. end
  64. end
  65. end

lib/bcdice/game_system/UnsungDuet_Korean.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/UnsungDuet"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class UnsungDuet_Korean < UnsungDuet
  6. 1 ID = 'UnsungDuet:Korean'
  7. 1 NAME = '언성 듀엣'
  8. 1 SORT_KEY = '国際化:Korean:언성 듀엣'
  9. 1 HELP_MESSAGE = <<~MESSAGETEXT
  10. ■ 시프터 용 판정 (shifter, UDS)
  11. 1D10을 다이스롤 해서 판정을 행합니다.
  12. 예) shifter, UDS, shifter>=5, shifter+1>=6
  13. ■ 바인더 용 판정 (binder, UDB)
  14. 2D6을 다이스롤 해서 판정을 행합니다.
  15. 예) binder, UDB, binder>=5, binder+1>=6
  16. ■ 변이표
  17. ・상처 (HIN, HInjury)
  18. ・몸 상태의 변화 (HPH, HPhysical)
  19. ・공포 (HFE, HFear)
  20. ・환상화 (HFA, HFantasy)
  21. ・정신 (HMI, HMind)
  22. ・기타 (HOT, HOther)
  23. MESSAGETEXT
  24. 1 register_prefix_from_super_class()
  25. 1 def initialize(command)
  26. 28 super(command)
  27. 28 @locale = :ko_kr
  28. end
  29. 1 TABLES = translate_tables(:ko_kr)
  30. end
  31. end
  32. end

lib/bcdice/game_system/Utakaze.rb

100.0% lines covered

83.33% branches covered

94 relevant lines. 94 lines covered and 0 lines missed.
36 total branches, 30 branches covered and 6 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Utakaze < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Utakaze'
  7. # ゲームシステム名
  8. 1 NAME = 'ウタカゼ'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'うたかせ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・行為判定ロール(nUK)
  14. n個のサイコロで行為判定ロール。ゾロ目の最大個数を成功レベルとして表示。nを省略すると2UK扱い。
  15. 例)3UK :サイコロ3個で行為判定
  16. 例)UK :サイコロ2個で行為判定
  17. ・難易度付き行為判定ロール(nUK>=t)
  18. tに難易度を指定した行為判定ロール。
  19. 成功レベルと難易度tを比べて成否を判定します。
  20. 例)6UK>=3 :サイコロ6個で行為判定して、成功レベル3が出れば成功。
  21. ・クリティカルコール付き行為判定ロール(nUK@c or nUKc)
  22. cに「龍のダイス目」を指定した行為判定ロール。
  23. ゾロ目ではなく、cと同じ値の出目数x2が成功レベルとなります。難易度の指定も可能です。
  24. 例)3UK@5 :龍のダイス「月」でクリティカルコール宣言したサイコロ3個の行為判定
  25. ・対抗判定ロール(nUR[@c], nUO[@c]) n:ダイス数 c:クリティカルコール
  26.  行為判定ロールと同様にロールするが、最期に成功レベルとセット数から求めたマジックナンバーが表示される。
  27.  マジックナンバーの大きいものが成功、同値は引き分け。
  28.  ダイスは18個まで対応。
  29. MESSAGETEXT
  30. 1 register_prefix('\d*U[KRO]')
  31. 1 def eval_game_system_specific_command(command)
  32. 48 debug('eval_game_system_specific_command command', command)
  33. 48 check_roll(command) ||
  34. opposed_roll(command)
  35. end
  36. 1 private
  37. 1 DRAGON_DICE_NAME = {
  38. 1 => "風",
  39. 2 => "雨",
  40. 3 => "雲",
  41. 4 => "影",
  42. 5 => "月",
  43. 6 => "歌"
  44. }.freeze
  45. 1 def check_roll(command)
  46. 48 m = /^(\d+)?UK(@?(\d))?(>=(\d+))?$/i.match(command)
  47. 48 else: 38 then: 10 return nil unless m
  48. 38 base = (m[1] || 2).to_i
  49. 38 crit = m[3].to_i
  50. 38 diff = m[5].to_i
  51. 38 base = getValue(base)
  52. 38 crit = getValue(crit)
  53. 38 then: 0 else: 38 return nil if base < 1
  54. 38 then: 0 else: 38 crit = 6 if crit > 6
  55. 38 dice_list = @randomizer.roll_barabara(base, 6).sort
  56. 38 result = get_roll_result(dice_list, crit, diff)
  57. sequence = [
  58. 38 command,
  59. "(#{base}D6)",
  60. "[#{dice_list.join(',')}]",
  61. result.text
  62. ]
  63. 38 result.text = sequence.join(" > ")
  64. 38 return result
  65. end
  66. 1 def get_roll_result(diceList, crit, diff)
  67. 38 success, maxnum, setCount = getSuccessInfo(diceList, crit)
  68. 38 sequence = []
  69. 38 then: 18 else: 20 if isDragonDice(crit)
  70. 18 sequence.push("龍のダイス「#{DRAGON_DICE_NAME[crit]}」(#{crit})を使用")
  71. end
  72. 38 then: 29 if success
  73. 29 sequence.push("成功レベル:#{maxnum} (#{setCount}セット)")
  74. else: 9 else
  75. 9 sequence.push("失敗")
  76. 9 return Result.failure(sequence.join(" > "))
  77. end
  78. 29 then: 27 if diff == 0
  79. 27 else: 2 return Result.success(sequence.join(" > ")) # 難易度なしでも成功として扱う
  80. 2 then: 1 elsif maxnum >= diff
  81. 1 sequence.push("成功")
  82. 1 return Result.success(sequence.join(" > "))
  83. else: 1 else
  84. 1 sequence.push("失敗")
  85. 1 return Result.failure(sequence.join(" > "))
  86. end
  87. end
  88. # 対抗判定
  89. 1 def opposed_roll(command)
  90. 10 m = /^(\d+)?U[R|O](@?(\d))?$/i.match(command)
  91. 10 else: 10 then: 0 return nil unless m
  92. 10 base = (m[1] || 2).to_i
  93. 10 crit = m[3].to_i
  94. 10 base = getValue(base)
  95. 10 crit = getValue(crit)
  96. 10 then: 0 else: 10 return nil if base < 1 || base > 18
  97. 10 then: 0 else: 10 crit = 6 if crit > 6
  98. 10 dice_list = @randomizer.roll_barabara(base, 6).sort
  99. 10 result = get_opposed_roll_result(dice_list, crit)
  100. sequence = [
  101. 10 command,
  102. "(#{base}D6)",
  103. "[#{dice_list.join(',')}]",
  104. result.text
  105. ]
  106. 10 result.text = sequence.join(" > ")
  107. 10 return result
  108. end
  109. 1 def get_opposed_roll_result(diceList, crit)
  110. 10 success, maxnum, setCount = getSuccessInfo(diceList, crit)
  111. 10 sequence = []
  112. 10 then: 4 else: 6 if isDragonDice(crit)
  113. 4 sequence.push("龍のダイス「#{DRAGON_DICE_NAME[crit]}」(#{crit})を使用")
  114. end
  115. 10 then: 8 if success
  116. 8 sequence.push("成功レベル:#{maxnum} (#{setCount}セット)")
  117. 8 sequence.push("(" + format("%#02d%#1d", maxnum, setCount) + ")")
  118. 8 return Result.success(sequence.join(" > ")) # 出力上は成功として扱う
  119. else: 2 else
  120. 2 sequence.push("(000)")
  121. 2 return Result.failure(sequence.join(" > "))
  122. end
  123. end
  124. 1 def getSuccessInfo(diceList, crit)
  125. 48 debug("checkSuccess diceList, crit", diceList, crit)
  126. 48 diceCountHash = getDiceCountHash(diceList, crit)
  127. 48 debug("diceCountHash", diceCountHash)
  128. 48 maxnum = 0
  129. 48 successDiceList = []
  130. 48 then: 22 else: 26 countThreshold = (isDragonDice(crit) ? 1 : 2)
  131. 48 diceCountHash.each do |dice, count|
  132. 87 then: 53 else: 34 maxnum = count if count > maxnum
  133. 87 then: 46 else: 41 successDiceList << dice if count >= countThreshold
  134. end
  135. 48 debug("successDiceList", successDiceList)
  136. 48 else: 37 if successDiceList.size <= 0
  137. then: 11 # 失敗:ゾロ目無し(全部違う)
  138. 11 return false, 0, 0
  139. end
  140. # 竜のダイスの場合
  141. 37 then: 18 else: 19 maxnum *= 2 if isDragonDice(crit)
  142. # 成功:ゾロ目あり
  143. 37 return true, maxnum, successDiceList.size
  144. end
  145. # 各ダイスの個数を数えてHashにする
  146. 1 def getDiceCountHash(dice_list, critical)
  147. 48 dice_list
  148. 214 .select { |dice| isNomalDice(critical) || dice == critical }
  149. .group_by(&:itself)
  150. .transform_values(&:size)
  151. end
  152. 1 def isNomalDice(crit)
  153. 214 !isDragonDice(crit)
  154. end
  155. 1 def isDragonDice(crit)
  156. 347 (crit != 0)
  157. end
  158. 1 def getValue(number)
  159. 96 then: 0 else: 96 return 0 if number > 100
  160. 96 return number
  161. end
  162. end
  163. end
  164. end

lib/bcdice/game_system/VampireTheMasquerade5th.rb

100.0% lines covered

100.0% branches covered

89 relevant lines. 89 lines covered and 0 lines missed.
44 total branches, 44 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class VampireTheMasquerade5th < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'VampireTheMasquerade5th'
  7. # ゲームシステム名
  8. 1 NAME = 'Vampire: The Masquerade 5th Edition'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'うあんはいあさますかれえと5'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定コマンド(nVMFx+x または nVMIxHx)
  14. VMFコマンドはHungerダイスとダイスプールを個別に指定する。
  15. VMIコマンドはHungerダイスをダイスプールの内数として指定する。
  16. 例:難易度2、9ダイスプールでHungerダイス3個の場合、それぞれ以下のようなコマンドとなる。
  17. 2VMF6+3
  18. 2VMI9H3
  19. 難易度指定:成功数のカウント、判定成功と失敗、Critical処理、Critical Win、Total Failureのチェックを行う
  20. (Hungerダイスがある場合)Messy CriticalとBestial Failureチェックを行う
  21. 例) (難易度)VMF(通常ダイス)+(Hungerダイス)
  22. (難易度)VMF(通常ダイス)
  23. (難易度)VMI(通常ダイス)H(Hungerダイス)
  24. (難易度)VMI(通常ダイス)
  25. 難易度省略:成功数のカウント、判定失敗、Critical処理、Total Failure、(Hungerダイスがある場合)Bestial Failureチェックを行う
  26. 判定成功、Messy Criticalのチェックを行わない
  27. Critical Win、(Hungerダイスがある場合)Bestial Failure、Messy Criticalのヒントを出力
  28. 例) VMF(通常ダイス)+(Hungerダイス)
  29. VMF(通常ダイス)
  30. VMI(通常ダイス)H(Hungerダイス)
  31. VMI(通常ダイス)
  32. 難易度0指定:Critical処理と成功数のカウントを行い、全てのチェックを行わない
  33. 例) 0VMF(通常ダイス)+(Hungerダイス)
  34. 0VMF(通常ダイス)
  35. 0VMI(通常ダイス)+(Hungerダイス)
  36. 0VMI(通常ダイス)
  37. MESSAGETEXT
  38. 1 DIFFICULTY_INDEX = 1
  39. 1 DICE_POOL_HUNGER_DICE_NO_INCLUDED_INDEX = 5
  40. 1 HUNGER_DICE_NO_INCLUDED_INDEX = 7
  41. 1 COMMAND_HUNGER_DICE_INCLUDED_INDEX = 9
  42. 1 DICE_POOL_HUNGER_DICE_INCLUDED_INDEX = 10
  43. 1 HUNGER_DICE_INCLUDED_INDEX = 12
  44. # 難易度に指定可能な特殊値
  45. 1 NOT_CHECK_SUCCESS = -1 # 判定成功にかかわるチェックを行わない(判定失敗に関わるチェックは行う)
  46. 1 register_prefix('\d*(VMF|(VMI\d*(H\d?)?))')
  47. 1 def eval_game_system_specific_command(command)
  48. 181 m = /\A(\d+)?(((VMF)(\d+)(\+(\d+))?)|((VMI)(\d+)(H(\d+))?))$/.match(command)
  49. 181 else: 180 then: 1 unless m
  50. 1 return ''
  51. end
  52. 180 dice_pool, hunger_dice_pool = get_dice_pools(m)
  53. 180 then: 1 else: 179 if dice_pool < 0
  54. 1 return "ダイスプール0のときにHungerダイスは指定できません。"
  55. end
  56. 179 then: 2 else: 177 if hunger_dice_pool > 5
  57. 2 return "Hungerダイス指定は5ダイスが最大です。"
  58. end
  59. 177 dice_text, success_dice, ten_dice, = make_dice_roll(dice_pool)
  60. 177 result_text = "(#{dice_pool}D10"
  61. 177 then: 126 if hunger_dice_pool >= 0
  62. 126 hunger_dice_text, hunger_success_dice, hunger_ten_dice, hunger_botch_dice = make_dice_roll(hunger_dice_pool)
  63. 126 ten_dice += hunger_ten_dice
  64. 126 success_dice += hunger_success_dice
  65. 126 result_text = "#{result_text}+#{hunger_dice_pool}D10) > [#{dice_text}]+[#{hunger_dice_text}] "
  66. else: 51 else
  67. 51 hunger_ten_dice = 0
  68. 51 hunger_botch_dice = 0
  69. 51 result_text = "#{result_text}) > [#{dice_text}] "
  70. end
  71. 177 success_dice += get_critical_success(ten_dice)
  72. 177 then: 110 else: 67 difficulty = m[DIFFICULTY_INDEX] ? m[DIFFICULTY_INDEX].to_i : NOT_CHECK_SUCCESS
  73. 177 return get_roll_result(result_text, success_dice, ten_dice, hunger_ten_dice, hunger_botch_dice, difficulty)
  74. end
  75. 1 private
  76. 1 def get_dice_pools(m)
  77. 180 hunger_dice_included_command = m[COMMAND_HUNGER_DICE_INCLUDED_INDEX]
  78. 180 if hunger_dice_included_command && hunger_dice_included_command == "VMI"
  79. then: 95 # Hunger Diceを内数処理するの場合
  80. 95 then: 25 else: 70 hunger_dice_pool = m[HUNGER_DICE_INCLUDED_INDEX].nil? ? -1 : m[HUNGER_DICE_INCLUDED_INDEX].to_i
  81. 95 dice_pool_value = m[DICE_POOL_HUNGER_DICE_INCLUDED_INDEX].to_i
  82. 95 then: 25 else: 70 dice_pool = dice_pool_value - (hunger_dice_pool < 0 ? 0 : hunger_dice_pool)
  83. 95 else: 65 if dice_pool_value > 0 && hunger_dice_pool >= dice_pool_value
  84. then: 30 # 1 以上のダイスプール、かつ、Hungerダイスがダイスプール以上のとき、ダイスプールが全てHungerダイスになる。
  85. 30 dice_pool = 0
  86. 30 hunger_dice_pool = dice_pool_value
  87. end
  88. else
  89. else: 85 # Hunger DiceがPLによる内数指定の場合
  90. 85 then: 26 else: 59 hunger_dice_pool = m[HUNGER_DICE_NO_INCLUDED_INDEX].nil? ? -1 : m[HUNGER_DICE_NO_INCLUDED_INDEX].to_i
  91. 85 dice_pool = m[DICE_POOL_HUNGER_DICE_NO_INCLUDED_INDEX].to_i
  92. end
  93. 180 return dice_pool, hunger_dice_pool
  94. end
  95. 1 def get_roll_result(result_text, success_dice, ten_dice, hunger_ten_dice, hunger_botch_dice, difficulty)
  96. 177 result_text = "#{result_text} 成功数=#{success_dice}"
  97. 177 is_critical = ten_dice >= 2
  98. 177 then: 74 if difficulty > 0
  99. 74 result_text = "#{result_text} 難易度=#{difficulty}"
  100. 74 then: 44 if success_dice >= difficulty
  101. 44 result_text = "#{result_text} 差分=#{success_dice - difficulty}"
  102. 44 then: 17 if hunger_ten_dice > 0 && is_critical
  103. 17 else: 27 return Result.critical("#{result_text}:判定成功! [Messy Critical]")
  104. 27 then: 11 else: 16 elsif is_critical
  105. 11 return Result.critical("#{result_text}:判定成功! [Critical Win]")
  106. end
  107. 16 return Result.success("#{result_text}:判定成功!")
  108. else: 30 else
  109. 30 then: 9 else: 21 if hunger_botch_dice > 0
  110. 9 return Result.fumble("#{result_text}:判定失敗! [Bestial Failure]")
  111. end
  112. 21 then: 9 else: 12 if success_dice == 0
  113. 9 return Result.fumble("#{result_text}:判定失敗! [Total Failure]")
  114. end
  115. 12 return Result.failure("#{result_text}:判定失敗!")
  116. else: 103 end
  117. 103 then: 67 else: 36 elsif difficulty < 0
  118. 67 then: 23 if success_dice == 0
  119. 23 then: 8 else: 15 if hunger_botch_dice > 0
  120. 8 return Result.fumble("#{result_text}:判定失敗! [Bestial Failure]")
  121. end
  122. 15 return Result.fumble("#{result_text}:判定失敗! [Total Failure]")
  123. else: 44 else
  124. 44 then: 20 else: 24 if hunger_botch_dice > 0
  125. 20 result_text = "#{result_text}\n 判定失敗なら [Bestial Failure]"
  126. end
  127. 44 then: 15 if hunger_ten_dice > 0 && is_critical
  128. 15 else: 29 result_text = "#{result_text}\n 判定成功なら [Messy Critical]"
  129. 29 then: 8 else: 21 elsif is_critical
  130. 8 result_text = "#{result_text}\n 判定成功なら [Critical Win]"
  131. end
  132. 44 return result_text.to_s
  133. end
  134. end
  135. # 難易度0指定(=全ての判定チェックを行わない)
  136. 36 return result_text.to_s
  137. end
  138. 1 def get_critical_success(ten_dice)
  139. # 10の目が2個毎に追加2成功
  140. 177 return ((ten_dice / 2) * 2)
  141. end
  142. 1 def make_dice_roll(dice_pool)
  143. 303 dice_list = @randomizer.roll_barabara(dice_pool, 10)
  144. 303 dice_text = dice_list.join(',')
  145. 960 success_dice = dice_list.count { |x| x >= 6 }
  146. 303 ten_dice = dice_list.count(10)
  147. 303 botch_dice = dice_list.count(1)
  148. 303 return dice_text, success_dice, ten_dice, botch_dice
  149. end
  150. end
  151. end
  152. end

lib/bcdice/game_system/Ventangle.rb

96.15% lines covered

90.0% branches covered

52 relevant lines. 50 lines covered and 2 lines missed.
20 total branches, 18 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/base'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Ventangle < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'Ventangle'
  8. # ゲームシステム名
  9. 1 NAME = 'Ventangle'
  10. # ゲームシステム名の読みがな
  11. #
  12. # 「ゲームシステム名の読みがなの設定方法」(docs/dicebot_sort_key.md)を参考にして
  13. # 設定してください
  14. 1 SORT_KEY = 'うえんたんくる'
  15. # ダイスボットの使い方
  16. 1 HELP_MESSAGE = <<~MESSAGETEXT
  17. 基本書式 VTn@s#f$g>=T n=ダイス数(省略時2) s=スペシャル値(省略時12) f=ファンブル値(省略時2) g=レベルギャップ判定値(省略可) T=目標値(省略可)
  18. 例:
  19. VT デフォルトのスペシャル値・ファンブル値の判定を行う
  20. VT@10#3 スペシャル値10、ファンブル値3の判定を行う
  21. VT3@10#3 スペシャル値10、ファンブル値3の判定を、アドバンテージを1点消費してダイス3つで行う
  22. VT>=5 デフォルトのスペシャル値・ファンブル値で目標値5の判定を行う
  23. VT@10#3>=5 スペシャル値10、ファンブル値3で目標値5の判定を行う
  24. VT@10#3$5>=5 スペシャル値10、ファンブル値3で目標値5の判定を行う。この際達成値が目標値より5以上大きい場合、ギャップボーナスを表示する
  25. VT3@10#3>=5 スペシャル値10、ファンブル値3で目標値5の判定を、アドバンテージを1点消費してダイス3つで行う
  26. VT3@10#3$4>=5 スペシャル値10、ファンブル値3で目標値5の判定を、アドバンテージを1点消費してダイス3つで行う。この際達成値が目標値より4以上大きい場合、ギャップボーナスを表示する
  27. MESSAGETEXT
  28. # 既定のスペシャル値
  29. 1 DEFAULT_SPECIAL_VALUE = 12
  30. # 既定のファンブル値
  31. 1 DEFAULT_FUMBLE_VALUE = 2
  32. # 規定のダイス個数
  33. 1 DEFAULT_DICE_NUM = 2
  34. # ダイスボットで使用するコマンドを配列で列挙する
  35. 1 register_prefix('VT')
  36. 1 def eval_game_system_specific_command(command)
  37. 47 debug("eval_game_system_specific_command Begin")
  38. 47 parser = Command::Parser.new('VT', round_type: round_type)
  39. .enable_critical
  40. .enable_fumble
  41. .enable_dollar
  42. .enable_suffix_number
  43. .restrict_cmp_op_to(nil, :>=)
  44. 47 cmd = parser.parse(command)
  45. 47 else: 47 then: 0 unless cmd
  46. return nil
  47. end
  48. 47 dice_num = cmd.suffix_number || DEFAULT_DICE_NUM
  49. 47 then: 0 else: 47 if dice_num < DEFAULT_DICE_NUM
  50. return nil
  51. end
  52. 47 dice_list = @randomizer.roll_barabara(dice_num, 6)
  53. 47 if dice_num > 2
  54. then: 16 # 出目の順序を保存して上位2つの出目を取得
  55. 16 j = 0 # 安定ソートのために利用 cf. https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/sort_by.html
  56. 80 using_list = dice_list.map.with_index { |x, i| {index: i, value: x} }
  57. 64 .sort_by { |x| [x[:value], j += 1] }.reverse.take(2)
  58. 64 .sort_by { |x| x[:index] }.map { |x| x[:value] }
  59. else: 31 else
  60. 31 using_list = dice_list
  61. end
  62. 47 dice_total = using_list.sum
  63. 47 total = dice_total + cmd.modify_number
  64. 47 result = compare(dice_total, total, cmd)
  65. advantage_str =
  66. 47 then: 16 else: 31 if dice_num > 2
  67. 16 using_list.to_s
  68. end
  69. modifier_str =
  70. 47 then: 39 else: 8 if cmd.modify_number > 0
  71. 39 "#{dice_total}#{Format.modifier(cmd.modify_number)}"
  72. end
  73. level_gap_str =
  74. 47 then: 8 else: 39 if cmd.target_number && cmd.dollar && result.success? && (gap = total - cmd.target_number) >= cmd.dollar
  75. 8 "ギャップボーナス(#{gap})"
  76. end
  77. sequence = [
  78. 47 cmd.to_s,
  79. dice_list.to_s,
  80. advantage_str,
  81. modifier_str,
  82. total.to_s,
  83. result.text,
  84. level_gap_str,
  85. ].compact
  86. 47 result.text = sequence.join(" > ")
  87. 47 return result
  88. end
  89. 1 def compare(dice_total, total, cmd)
  90. 47 special = cmd.critical || DEFAULT_SPECIAL_VALUE
  91. 47 fumble = cmd.fumble || DEFAULT_FUMBLE_VALUE
  92. 47 then: 10 if dice_total <= fumble
  93. 10 else: 37 return Result.fumble('ファンブル')
  94. 37 then: 11 else: 26 elsif dice_total >= special
  95. 11 return Result.critical('スペシャル')
  96. end
  97. 26 then: 21 if cmd.target_number
  98. 21 then: 14 if total.send(cmd.cmp_op, cmd.target_number)
  99. 14 return Result.success('成功')
  100. else: 7 else
  101. 7 return Result.failure('失敗')
  102. end
  103. else: 5 else
  104. 5 return Result.new(nil)
  105. end
  106. end
  107. end
  108. end
  109. end

lib/bcdice/game_system/Ventangle_Korean.rb

96.15% lines covered

90.0% branches covered

52 relevant lines. 50 lines covered and 2 lines missed.
20 total branches, 18 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/base'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Ventangle_Korean < Ventangle
  6. # ゲームシステムの識別子
  7. 1 ID = 'Ventangle:Korean'
  8. # ゲームシステム名
  9. 1 NAME = '벤탱글'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = '国際化:Korean:벤탱글'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~MESSAGETEXT
  14. 기본 양식 VTn@s#f$g>=T n=주사위 개수(생략 시 2) s=스페셜치(생략 시 12) f=펌블치(생략 시 2) g=레벨 갭 판정치(생략 가능) T=목표치(생략 가능)
  15. 예시:
  16. VT 기본 스페셜치, 펌블치로 판정
  17. VT@10#3 스페셜치 10、펌블치 3으로 판정
  18. VT3@10#3 어드밴티지 1점을 사용해 스페셜치 10, 펌블치 3 판정을 주사위 3개로 판정
  19. VT>=5 기본 스페셜치, 펌블치로 목표치 5 판정
  20. VT@10#3>=5 스페셜치 10, 펌블치 3으로 목표치 5 판정
  21. VT@10#3$5>=5 스페셜치 10, 펌블치 3으로 목표치 5 판정. 이때 달성치가 목표치보다 5이상 큰 경우, 갭 보너스를 표시
  22. VT3@10#3>=5 어드밴티지 1점을 사용해 스페셜치 10, 펌블치 3, 목표치 5 판정을 주사위 3개로 판정
  23. VT3@10#3$4>=5 어드밴티지 1점을 사용해 스페셜치 10, 펌블치 3, 목표치 5 판정을 주사위 3개로 판정. 이때 달성치가 목표치보다 4이상 큰 경우, 갭 보너스를 표시
  24. MESSAGETEXT
  25. # 既定のスペシャル値
  26. 1 DEFAULT_SPECIAL_VALUE = 12
  27. # 既定のファンブル値
  28. 1 DEFAULT_FUMBLE_VALUE = 2
  29. # 規定のダイス個数
  30. 1 DEFAULT_DICE_NUM = 2
  31. # ダイスボットで使用するコマンドを配列で列挙する
  32. 1 register_prefix('VT')
  33. 1 def eval_game_system_specific_command(command)
  34. 47 debug("eval_game_system_specific_command Begin")
  35. 47 parser = Command::Parser.new('VT', round_type: round_type)
  36. .enable_critical
  37. .enable_fumble
  38. .enable_dollar
  39. .enable_suffix_number
  40. .restrict_cmp_op_to(nil, :>=)
  41. 47 cmd = parser.parse(command)
  42. 47 else: 47 then: 0 unless cmd
  43. return nil
  44. end
  45. 47 dice_num = cmd.suffix_number || DEFAULT_DICE_NUM
  46. 47 then: 0 else: 47 if dice_num < DEFAULT_DICE_NUM
  47. return nil
  48. end
  49. 47 dice_list = @randomizer.roll_barabara(dice_num, 6)
  50. 47 if dice_num > 2
  51. then: 16 # 出目の順序を保存して上位2つの出目を取得
  52. 16 j = 0 # 安定ソートのために利用 cf. https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/sort_by.html
  53. 80 using_list = dice_list.map.with_index { |x, i| {index: i, value: x} }
  54. 64 .sort_by { |x| [x[:value], j += 1] }.reverse.take(2)
  55. 64 .sort_by { |x| x[:index] }.map { |x| x[:value] }
  56. else: 31 else
  57. 31 using_list = dice_list
  58. end
  59. 47 dice_total = using_list.sum
  60. 47 total = dice_total + cmd.modify_number
  61. 47 result = compare(dice_total, total, cmd)
  62. advantage_str =
  63. 47 then: 16 else: 31 if dice_num > 2
  64. 16 using_list.to_s
  65. end
  66. modifier_str =
  67. 47 then: 39 else: 8 if cmd.modify_number > 0
  68. 39 "#{dice_total}#{Format.modifier(cmd.modify_number)}"
  69. end
  70. level_gap_str =
  71. 47 then: 8 else: 39 if cmd.target_number && cmd.dollar && result.success? && (gap = total - cmd.target_number) >= cmd.dollar
  72. 8 "갭 보너스(#{gap})"
  73. end
  74. sequence = [
  75. 47 cmd.to_s,
  76. dice_list.to_s,
  77. advantage_str,
  78. modifier_str,
  79. total.to_s,
  80. result.text,
  81. level_gap_str,
  82. ].compact
  83. 47 result.text = sequence.join(" > ")
  84. 47 return result
  85. end
  86. 1 def compare(dice_total, total, cmd)
  87. 47 special = cmd.critical || DEFAULT_SPECIAL_VALUE
  88. 47 fumble = cmd.fumble || DEFAULT_FUMBLE_VALUE
  89. 47 then: 10 if dice_total <= fumble
  90. 10 else: 37 return Result.fumble('펌블')
  91. 37 then: 11 else: 26 elsif dice_total >= special
  92. 11 return Result.critical('스페셜')
  93. end
  94. 26 then: 21 if cmd.target_number
  95. 21 then: 14 if total.send(cmd.cmp_op, cmd.target_number)
  96. 14 return Result.success('성공')
  97. else: 7 else
  98. 7 return Result.failure('실패')
  99. end
  100. else: 5 else
  101. 5 return Result.new(nil)
  102. end
  103. end
  104. end
  105. end
  106. end

lib/bcdice/game_system/Villaciel.rb

98.4% lines covered

83.15% branches covered

187 relevant lines. 184 lines covered and 3 lines missed.
89 total branches, 74 branches covered and 15 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Villaciel < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Villaciel'
  7. # ゲームシステム名
  8. 1 NAME = '蒼天のヴィラシエル'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'そうてんのういらしえる'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定        nVBS[>=d]
  14.  []内省略時は達成数の計算のみ。トライアンフあり。
  15.  n: ダイス数、d: 難易度
  16. ・フロンティア判定  nVF
  17.  n: ダイス数
  18.  nVBSを行い、うでまえ表を参照した結果を表示します。
  19. ・採掘スキル判定   nVM
  20.  n: ダイス数
  21.  判定に成功した場合、自動的に獲得できるアイテム数も表示されます。
  22. ・宝石加工スキル判定 nVG
  23.  n: ダイス数
  24. ・前職表       PJ[x] x=V,A
  25.  []内は省略可能。
  26.  PJ, PJV: 「蒼天のヴィラシエル」掲載の前職表 PJA: 「白雲のアルメサール」掲載の前職表
  27. ・ぷちクエスト表   PQ[x] x=V,A
  28.  []内は省略可能。
  29.  PQ, PQV: 「蒼天のヴィラシエル」掲載のぷちクエスト表 PQA: 「白雲のアルメサール」掲載のぷちクエスト表
  30. ・アクシデント表   AC
  31. ・もふもふ表     MMx x=I,A,V,VV,VA,D
  32. MMI: 昆虫 MMA: 動物 MMV, MMVV: ヴィラシエル種(「蒼天のヴィラシエル」掲載) MMVA: ヴィラシエル種(「白雲のアルメサール」掲載) MMD: 鋼龍種
  33. ・釣り表       Fx x=L,R,W,G,B,C,S
  34.  FL: 湖 FR: 河 FW: 白雲 FG: 灰雲 FB: 黒雲 FC: 共通 FS: 塩湖
  35. ・不食植物表     IP[x] x=V,A
  36.  IP, IPV: 「蒼天のヴィラシエル」掲載の不食植物表 IPA: 「白雲のアルメサール」掲載の不食植物表
  37. ・可食植物表     EP[x][n] x=V,A
  38.  []内は省略可能。
  39.  n: 可食植物表番号
  40.  EP[n], EPV[n]: 「蒼天のヴィラシエル」掲載の可食植物表。[]内省略時はnを1D6で決定し、EPVnを実行。ただし、1D6の出目が6ならば、「好きな表を選んでおっけー!」と表示。
  41.  EPA[n]: 「白雲のアルメサール」掲載の可食植物表。[]内省略時は1D6を振り、出目が偶数ならばEPA1、奇数ならばEPA2を実行。
  42. ・変異植物表     MP
  43. ・改良種表      IS
  44. MESSAGETEXT
  45. 1 register_prefix('\d+VBS(>=\d+)?', '\d+VF', '\d+VM', '\d+VG', 'PJ[VA]?', 'PQ[VA]?', 'AC', 'MM([IAD]|V[VA]?)', 'F[LRWGBCS]', 'IP[VA]?', 'EP[VA]?', 'MP', 'IS')
  46. 1 def initialize(command)
  47. 51 super(command)
  48. 51 @d66_sort_type = D66SortType::NO_SORT # D66あり。ただし、現行ルールにある6x6の表については別のコマンドを用意
  49. 51 @round_type = RoundType::CEIL # 端数は切り上げ
  50. end
  51. 1 def eval_game_system_specific_command(command)
  52. 51 else: 0 case command
  53. when: 6 when /\d+VBS/
  54. 6 resolute_action(command)
  55. when: 3 when /\d+VF/
  56. 3 resolute_frontier_action(command)
  57. when: 2 when /\d+VM/
  58. 2 resolute_mining_action(command)
  59. when: 2 when /\d+VG/
  60. 2 resolute_cutting_gem_action(command)
  61. when: 3 when /PJ[VA]?/
  62. 3 use_previous_job_chart(command)
  63. when: 3 when /PQ[VA]?/
  64. 3 use_petit_quest_chart(command)
  65. when: 1 when 'AC'
  66. 1 use_accident_chart(command)
  67. when: 6 when /MM([IAD]|V[VA]?)/
  68. 6 use_mohumohu_chart(command)
  69. when: 8 when /F[LRWGBCS]/
  70. 8 use_fishing_chart(command)
  71. when: 4 when /IP[VA]?/
  72. 4 use_inedible_plant_chart(command)
  73. when: 11 when /EP[VA]?\d?/
  74. 11 use_edible_plant_chart(command)
  75. when: 1 when 'MP'
  76. 1 use_mutant_plant_chart(command)
  77. when: 1 when 'IS'
  78. 1 use_improved_species_chart(command)
  79. end
  80. end
  81. 1 private
  82. 1 D6 = 6
  83. 1 LEAST_SUCCESS_ROLL = 4
  84. 1 SUCCESS_STR = ' > 成功'
  85. 1 FAILURE_STR = ' > 失敗'
  86. 1 def derive_achievement(num_dices, command)
  87. # 達成数計算の際にはトライアンフ「出目が6だったダイスは達成数2としてカウントする」を考慮する必要があるが、要は「達成数=成功数+出目が最大値だったダイスの数」になる
  88. 9 dice_list = @randomizer.roll_barabara(num_dices, D6)
  89. 9 dice_str = dice_list.join(",")
  90. 9 num_triumph_dices = dice_list.count(6)
  91. 63 num_successes = dice_list.count { |dice| dice >= LEAST_SUCCESS_ROLL }
  92. 9 achievement = num_successes + num_triumph_dices
  93. 9 output = "(#{command}) > [#{dice_str}] > 達成数: #{achievement}"
  94. 9 return achievement, output
  95. end
  96. 1 def resolute_action(command)
  97. 6 match_data = command.match(/(\d+)VBS(>=(\d+))?/)
  98. 6 num_dices = match_data[1].to_i
  99. 6 achievement, output = derive_achievement(num_dices, command)
  100. 6 else: 3 then: 3 return output unless match_data[2]
  101. 3 difficulty = match_data[3].to_i
  102. 3 then: 2 else: 1 output += achievement >= difficulty ? SUCCESS_STR : FAILURE_STR
  103. 3 return output
  104. end
  105. 1 SKILL_CHART = ['左に3マス、上に3マス動かす', '左に2マス、上に2マス動かす', '右か下に1マス動かしてもよい', '右に1マス、下に1マス動かす', '好きな方向に最大で3マス動かしてもよい(1マスでも良い)', '好きな方向に最大で5マス動かしてもよい(1〜3マスでもよい)'].freeze
  106. 1 def resolute_frontier_action(command)
  107. 3 num_dices = command.match(/(\d+)VF/)[1].to_i
  108. 3 achievement, output = derive_achievement(num_dices, command)
  109. chart_index =
  110. 3 case achievement
  111. when: 1 when 0..2
  112. 1 achievement
  113. when: 1 when 3, 4
  114. 1 3
  115. when: 1 when 5..8
  116. 1 4
  117. else: 0 else
  118. 5
  119. end
  120. 3 skill = SKILL_CHART[chart_index]
  121. 3 return "#{output} > #{skill}"
  122. end
  123. 1 def resolute_difficult_action(num_dices, least_success_roll, command)
  124. # 1個でもleast_success_roll以上の出目が出たら成功となる判定
  125. # 出目の最大値がnならば「1個でもn以上の出目が出た」ことになる
  126. 4 dice_list = @randomizer.roll_barabara(num_dices, D6)
  127. 4 dice_str = dice_list.join(',')
  128. 4 largest_roll = dice_list.max()
  129. 4 is_successful = largest_roll >= least_success_roll
  130. 4 output = "(#{command}) > [#{dice_str}]"
  131. 4 then: 2 else: 2 output += is_successful ? SUCCESS_STR : FAILURE_STR
  132. 4 return output, is_successful
  133. end
  134. 1 LEAST_MINING_SUCCESS_ROLL = 5
  135. 1 LEAST_GEM_SUCCESS_ROLL = 6
  136. 1 def resolute_mining_action(command)
  137. 2 num_dices = command.match(/(\d+)VM/)[1].to_i
  138. 2 output, is_successful = resolute_difficult_action(num_dices, LEAST_MINING_SUCCESS_ROLL, command)
  139. 2 else: 1 then: 1 return output unless is_successful
  140. 1 roll_result = @randomizer.roll_once(D6)
  141. 1 "#{output} > (1D6) > [#{roll_result}] > アイテムを#{roll_result}個獲得"
  142. end
  143. 1 def resolute_cutting_gem_action(command)
  144. 2 num_dices = command.match(/(\d+)VG/)[1].to_i
  145. 2 resolute_difficult_action(num_dices, LEAST_GEM_SUCCESS_ROLL, command)[0]
  146. end
  147. 1 VILLACIEL_PREVIOUS_JOB_CHART = [['農家: 知力+1 器用さ+1 開拓/1Lv',
  148. '漁師: 知力+1 ひらめき+1 釣り/1Lv',
  149. '狩人: 武力+1 ひらめき+1 穴掘り/1Lv',
  150. '鍛冶職人: 武力+1 器用さ+1 採掘/1Lv',
  151. '牧場主: 仲良し+2 開拓/1Lv',
  152. '採掘師: 器用さ+1 ひらめき+1 採掘/1Lv'].freeze,
  153. ['家事手伝い: 器用さ+1 仲良し+1 調理/1Lv',
  154. '調理師: 知力+1 ひらめき+1 調理/1Lv',
  155. '細工師: 器用さ+2 採掘/1Lv',
  156. '大工: 武力+1 器用さ+1 木こり/1Lv',
  157. '荒くれ者: 武力+2 穴掘り/1Lv',
  158. '王国騎士: 武力+1 知力+1 木こり/1Lv'].freeze].freeze
  159. 1 ARMESEAR_PREVIOUS_JOB_CHART = [['農家: 知力+1 器用さ+1 開拓/1Lv',
  160. '漁師: 知力+1 ひらめき+1 釣り/1Lv',
  161. '狩人: 武力+1 ひらめき+1 穴掘り/1Lv',
  162. '鍛冶職人: 武力+1 器用さ+1 採掘/1Lv',
  163. '牧場主: 仲良し+2 開拓/1Lv',
  164. '採掘師: 器用さ+1 ひらめき+1 採掘/1Lv'].freeze,
  165. ['羊飼い: 仲良し+2 もふもふ/1Lv',
  166. '芽拾い: 知力+1 武力+1 採集/1Lv',
  167. '服屋見習い: 器用さ+2 裁縫/1Lv',
  168. '革細工見習い: 知力+2 裁縫/1Lv',
  169. '商人: 知力+1 仲良し+1 基礎になるスキル/1Lv',
  170. '旅人: 武力+1 知力+1 基礎になるスキル/1Lv'].freeze,
  171. ['家事手伝い: 器用さ+1 仲良し+1 調理/1Lv',
  172. '調理師: 知力+1 ひらめき+1 調理/1Lv',
  173. '細工師: 器用さ+2 採掘/1Lv or 調合・細工/1Lv',
  174. '大工: 武力+1 器用さ+1 木こり/1Lv',
  175. '荒くれ者: 武力+2 穴掘り/1Lv',
  176. '王国騎士: 武力+1 知力+1 木こり/1Lv'].freeze].freeze
  177. 1 def use_previous_job_chart(command)
  178. 3 match_data = command.match(/PJ([VA]?)/)
  179. 3 then: 1 else: 2 chart_symbol = match_data[1] == '' ? 'V' : match_data[1]
  180. 3 roll_result1 = @randomizer.roll_once(D6)
  181. 3 when: 2 else: 0 chart_text, roll_result2 = case chart_symbol
  182. 2 when: 1 when 'V' then get_table_by_1d6(VILLACIEL_PREVIOUS_JOB_CHART[(roll_result1 - 1) / 3])
  183. 1 when 'A' then get_table_by_1d6(ARMESEAR_PREVIOUS_JOB_CHART[(roll_result1 - 1) / 2])
  184. end
  185. 3 when: 2 else: 0 chart_title = case chart_symbol
  186. 2 when: 1 when 'V' then '前職表(ヴィラシエル)'
  187. 1 when 'A' then '前職表(アルメサール)'
  188. end
  189. 3 "#{chart_title} > [#{roll_result1},#{roll_result2}] > #{chart_text}"
  190. end
  191. 1 VILLACIEL_PETIT_QUEST_CHART = [['家の補強のために: 【目的:木を1個納品】【報酬:各自2プサイ】見えを張っていい木材で家を作ったら木材が枯渇しちまった。頼む、原木を分けてくれないか?',
  192. '孫のために: 【目的:花を1個納品】【報酬:各自2プサイ】綺麗な花があればいい色に染められるだろうと思うてな。孫のために必要なの。',
  193. '人間界の草: 【目的:草を2個納品】【報酬:各自3プサイ】魔界にはない草が生えていると噂で聞いたことがある。その草がほしい。',
  194. '種の生存のために: 【目的:可食植物(改良種を除く)を1個納品】【報酬:各自1プサイ】育ちが悪い同種の植物と掛け合わせてみたいのでサンプルがほしい。',
  195. 'にんげんのたべもの!: 【目的:可食植物(改良種を除く)を1個納品】【報酬:各自2プサイ】ひゅーいあはなにをたべるの! たべたい!',
  196. 'まかいのたべものって?: 【目的:可食植物の改良種を2個納品】【報酬:各自3プサイ】まぞくさんはなにたべるですか! おしえてください。'].freeze,
  197. ['おうちなおしたいの!: 【目的:石材を1個納品】【報酬:各自1プサイ】おうちがぼろぼろだから、ママのかわりになおしたいの。',
  198. '娘の結婚式に必要なんだ!: 【目的:宝石を2個納品】【報酬:各自3プサイ】ちょっとさきなんですが、娘が結婚するので結婚式用の宝石を集めています。',
  199. '金属がたりない!: 【目的:金属を1個納品】【報酬:各自2プサイ】いい武器にはいい金属を。今回必要なのは……。',
  200. '村の聖堂を直したいんだ!: 【目的:石材を1個納品】【報酬:各自2プサイ】聖堂を直していたが石材がたりない!',
  201. '弟の甲冑に使うんだ!: 【目的:金属を2個納品】【報酬:各自3プサイ】最近、近くの鉱山から「ある金属」が姿を消した。',
  202. 'おねえちゃんのたんじょうびに: 【目的:宝石を1個納品】【報酬:各自2プサイ】たんじょうびぷれぜんとにほうせきあげたらおねえちゃんよろこぶかな?'].freeze,
  203. ['パパのために: 【目的:木材の家具を1個納品】【報酬:各自2プサイ】はたらいてばっかりのパパにプレゼントしたいの。おねがいします!',
  204. '癒やされたい……: 【目的:石材の家具を1個納品】【報酬:各自2プサイ】仕事時間は短いとはいえ、激務。めちゃつらい。癒しになる家具がほしい。',
  205. 'いい家具に囲まれてみたい: 【目的:金属の家具を1個納品】【報酬:各自2プサイ】開拓も最高だけど、他の島の人とも交流したい。人を呼べるような家を作るためには最高の家具が必要!',
  206. '家具の在庫不足: 【目的:木材の装飾品を1個納品】【報酬:各自3プサイ】困ったことに職人に逃げられた! このままじゃ、お店開けない!!',
  207. 'と、ともだちにあげるの!: 【目的:石材の装飾品を1個納品】【報酬:各自3プサイ】えっと、お、おきにいりのともだちがいるんだ。そ、そのこのたんじょうびだから、プレゼントしたくって。',
  208. '親の木に飾りを: 【目的:金属の装飾品を1個納品】【報酬:各自3プサイ】元気のない親の木を心配してペッコ達が大騒ぎしているんだ。君はいつまでも美しいよと伝えたくてね。一つ助力をお願いするよ。'].freeze,
  209. ['そちらの河魚を食してみたい: 【目的:河魚を2個納品】【報酬:各自3プサイ】おいしい河魚がいるときいたことがあるのです。さぁ、はやく、釣ってきてくださいまし。',
  210. '研究に使用したい: 【目的:湖魚を1個納品】【報酬:各自1プサイ】そちらの世界にある同名の魚が本当にこちらの世界にいるものと一緒か確かめたいのです。',
  211. 'しろいくもにすむおさかながみたい!: 【目的:白雲の雲魚を1個納品】【報酬:各自2プサイ】こっちにはしろいくもってなかなかないの! しろいくものおさかな、たべてみたいな。',
  212. '釣り師がいないのでお魚がほしい: 【目的:灰雲の雲魚を2個納品】【報酬:各自3プサイ】野菜や肉もいいが魚も食べたい……。頼む、魚を釣ってきてくれないか?',
  213. 'まっくろなくもにすむおさかな!: 【目的:黒雲の雲魚を1個納品】【報酬:各自2プサイ】まっくろなくもにはどんなさかながすんでるの? みせて、みせて!',
  214. '人間界では見られない魚が見たい!: 【目的:共通の雲魚を1個納品】【報酬:各自2プサイ】他の魚の雲を利用して泳ぎ回る魚がいると聞いたよ。ぜひ見せてほしいな。'].freeze].freeze
  215. 1 ARMESEAR_PETIT_QUEST_CHART = [['お祭り用の布が足りないの!: 【目的:布を2個納品】【報酬:各自4プサイ】お祭り前なのに、布職人が腰を痛めちゃったの!',
  216. 'お洋服がぼろぼろになっちゃったの: 【目的:布を1個納品】【報酬:各自2プサイ】おばあちゃんに作ってもらった服がボロボロになっちゃったから、なおしたいの。',
  217. 'ぎっくり腰からのヘルプ: 【目的:薪を3個納品】【報酬:各自3プサイ】仕事してたらぎっくり腰になっちゃったのだ。頼むのだ。',
  218. '不調には栄養たっぷりのミルクを: 【目的:ミルクを1個納品】【報酬:各自3プサイ】体調を崩しちゃったの。栄養満点のミルクを頂戴。',
  219. '材料がたりない!: 【目的:???の粗皮を1個納品】【報酬:各自3プサイ】革細工師を目指してるんだけど、皮が足りないんだ。種類は問わないから、早めに頼むよ。',
  220. '愛しのガードナーのために: 【目的:???の肉を1個納品】【報酬:各自3プサイ】ガードナーの調子が悪いから、栄養をつけさせたいんだ。肉はなんだっていい、とびっきりのを頼むよ。'].freeze,
  221. ['灯火をひとつ: 【目的:キャンドルを1個納品】【報酬:各自3プサイ】家の裏に知らない建物があるんだ。まっくらだから明かりが必要で……。',
  222. '布の色を頂戴: 【目的:染料を1個納品】【報酬:各自2プサイ】んー、コンテストのために布を織ったのだけど、色が決められないんだ。お願いするよ。',
  223. 'きれいなのお花を: 【目的:花を1個納品】【報酬:各自2プサイ】パパの誕生日プレゼントを妹と作りたいんだ。お願いできる?',
  224. '旅立ちのために: 【目的:衣類を1個納品】【報酬:各自15プサイ】旅立つ弟に服をプレゼントしたいんだ。',
  225. '納品物が足りない!: 【目的:革を1個納品】【報酬:各自4プサイ】どうしても納品する皮がたりない……頼む、なんとか用意できないか?',
  226. '求)照明: 【目的:照明を1個納品】【報酬:各自10プサイ】引っ越しする最中に照明を壊してしまった! 明日から明かりがないのはつらい……。作ってくれないか?'].freeze,
  227. ['装備の修復のため: 【目的:革を2個納品】【報酬:各自5プサイ】大事な装備が壊れちゃったんだ! 直すのに必要なんだけど、革を持っているかい?',
  228. '主に祝いの品を: 【目的:敷物を1個納品】【報酬:各自15プサイ】誕生日を迎える主にささやかなながらわたしからも祝いの品を送りたいのです。',
  229. '手料理を求めて: 【目的:出来栄え5の料理を1個納品】【報酬:各自5プサイ】たまには誰かの料理が食べたいんだ。',
  230. '釣り竿が折れちゃって……: 【目的:塩魚を2個納品】【報酬:各自3プサイ】釣り竿が折れちゃったから釣りができないんだ。一匹頼める?',
  231. '蝋がほしいの: 【目的:蝋を1個納品】【報酬:各自2プサイ】お兄ちゃんとパパの誕生日プレゼントを作るの。見つからないからお願いできる?',
  232. '美しさを求めて: 【目的:アルメサール産の花を1個納品】【報酬:各自3プサイ】美しいお花を摘んで来てくださらない? 美のために必要でしてよ。'].freeze].freeze
  233. 1 def use_petit_quest_chart(command)
  234. 3 match_data = command.match(/PQ([VA]?)/)
  235. 3 then: 1 else: 2 chart_symbol = match_data[1] == '' ? 'V' : match_data[1]
  236. 3 roll_result1 = @randomizer.roll_once(D6)
  237. 3 else: 0 chart_text, roll_result2 = case chart_symbol
  238. when: 2 when 'V'
  239. 2 when: 0 else: 0 chart_index = case roll_result1
  240. when: 1 when 1, 2 then 0
  241. 1 when: 1 when 3, 4 then 1
  242. 1 when: 0 when 5 then 2
  243. when 6 then 3
  244. end
  245. 2 when: 1 get_table_by_1d6(VILLACIEL_PETIT_QUEST_CHART[chart_index])
  246. 1 when 'A' then get_table_by_1d6(ARMESEAR_PETIT_QUEST_CHART[(roll_result1 - 1) / 2])
  247. end
  248. 3 when: 2 else: 0 chart_title = case chart_symbol
  249. 2 when: 1 when 'V' then 'ぷちクエスト表(ヴィラシエル)'
  250. 1 when 'A' then 'ぷちクエスト表(アルメサール)'
  251. end
  252. 3 "#{chart_title} > [#{roll_result1},#{roll_result2}] > #{chart_text}"
  253. end
  254. 1 ACCIDENT_CHART = ['飛び猪襲来!: 空飛ぶ猪が浮遊島めがけて突撃してきた! 建物が粉砕される前に迎撃だ!(「蒼天のヴィラシエル」P.46)',
  255. '嵐がくるぞ!: 嵐が来るらしいぞ! どれだけ対策できるかが鍵だ!(「蒼天のヴィラシエル」P.47)',
  256. '雨が降らないぞ!: おかしいなぁ、雨が降らないぞぉ……? こうなったら雨乞いの踊りだ!(「蒼天のヴィラシエル」P.48)',
  257. 'トビウオ流星群: きらきら光る流れ星……いや待て! あれはトビウオの群れだー!?(「蒼天のヴィラシエル」P.49)',
  258. 'すごい雷雨: すごい。ごろごろばりばり聞こえてくる。これは早々に対策しないと直撃するぞ!(「蒼天のヴィラシエル」P.50)',
  259. '野菜泥棒出現!: 畑の野菜が盗まれているぞ……? これは犯人を捕まえないと!(「蒼天のヴィラシエル」P.51)'].freeze
  260. 1 def use_accident_chart(_command)
  261. 1 chart_text, roll_result = get_table_by_1d6(ACCIDENT_CHART)
  262. 1 "アクシデント表 > [#{roll_result}] > #{chart_text}"
  263. end
  264. 1 def use_6x6_chart(chart, chart_name)
  265. # 6x6の表からランダムに参照する
  266. # chartは文字列の配列の配列であることを仮定
  267. # D66ロールによる表参照と近いが、D66の方は13, 42などの数値に対応した表なのに対し、こちらは「下3マス、右2マス」という風にセルを参照する
  268. 24 y_roll = @randomizer.roll_once(D6)
  269. 24 cell_text, x_roll = get_table_by_1d6(chart[y_roll - 1])
  270. 24 "#{chart_name} > [#{y_roll},#{x_roll}] > 下#{y_roll}マス、右#{x_roll}マス > #{cell_text}"
  271. end
  272. 1 MOHUMOHU_INSECT_CHART = [['小さな虫', '小さな虫', 'カマキリ', 'カマキリ', 'バッタ', 'クワガタ'].freeze,
  273. ['小さな虫', 'カラスアゲハ', 'カマキリ', 'バッタ', 'オオスカシバ', 'カイコ'].freeze,
  274. ['ハンミョウ', 'カラスアゲハ', 'カマキリ', 'バッタ', 'カイコ', 'トンボ'].freeze,
  275. ['ハンミョウ', 'カラスアゲハ', 'カラスアゲハ', 'チッチハチ', 'トンボ', 'トンボ'].freeze,
  276. ['クワガタ', 'カラスアゲハ', 'チッチハチ', 'チッチハチ', 'アリ', 'アリ'].freeze,
  277. ['クワガタ', 'チッチハチ', 'チッチハチ', 'チッチハチ', 'アリ', 'アリ'].freeze].freeze
  278. 1 MOHUMOHU_ANIMAL_CHART = [['トリサン', 'トリサン', 'ブタ', 'ヒツジ', 'タヌキ', 'タヌキ'].freeze,
  279. ['トリサン', 'ブタ', 'ヒツジ', 'ウッシ', 'キツネ', 'タヌキ'].freeze,
  280. ['ブタ', 'オグマ', 'ヒツジ', 'キツネ', 'キツネ', 'アタウサギ'].freeze,
  281. ['ブタ', 'ヒツジ', 'ヒツジ', 'リス', 'シシ', 'ヴィラシエル種(MMV)'].freeze,
  282. ['ウッシ', 'ウサギ', 'ウサギ', 'シシ', 'アタウサギ', 'オオカミ'].freeze,
  283. ['ウッシ', 'オグマ', 'クーマ', 'シシ', 'オオカミ', 'ヴィラシエル種(MMV)'].freeze].freeze
  284. 1 MOHUMOHU_VILLACIEL_CHART = [['ウドン', 'ウドン', 'オボン', 'オボン', 'オボン', 'オワン'].freeze,
  285. ['ウドン', 'ウドン', 'オボン', 'オワン', 'オワン', 'オワン'].freeze].freeze
  286. 1 MOHUMOHU_VILLACIEL2_CHART = [['すねーくあし', 'すねーくあし', 'すねーくあし', 'ウタヒ', 'オオトリサン', 'オオトリサン'].freeze,
  287. ['すねーくあし', 'すねーくあし', 'ホネホネ', 'オオトリサン', 'アマアマガニ', 'ホワホワ'].freeze,
  288. ['すねーくあし', 'ホネホネ', 'オオトリサン', 'ウタヒ', 'アマアマガニ', 'ペロリ'].freeze,
  289. ['オオトリサン', 'オオトリサン', 'ホネホネ', 'ホネホネ', 'ホワホワ', 'アマアマガニ'].freeze,
  290. ['ホネホネ', 'ウタヒ', 'アマアマガニ', 'ペロリ', 'ペロリ', 'ペロリ'].freeze,
  291. ['オオトリサン', 'ホワホワ', 'ホワホワ', 'アマアマガニ', 'ペロリ', 'ペロリ'].freeze].freeze
  292. 1 MOHUMOHU_DRAGON_CHART = [['モドモドリス', 'テロメ', 'モドモドリス', 'オジサン', 'オジサン', 'グロッチ'].freeze,
  293. ['テロメ', 'モドモドリス', 'オジサン', 'テロメ', 'ニホンツノ', 'グロッチ'].freeze,
  294. ['テロメ', 'グロッチ', 'グロッチ', 'グロッチ', 'オジサン', 'コディ'].freeze,
  295. ['モドモドリス', 'グロッチ', 'ニホンツノ', 'テロメ', 'テーリー', 'ケラプス'].freeze,
  296. ['オジサン', 'テロメ', 'テロメ', 'コディ', 'コディ', 'ケラプス'].freeze,
  297. ['コディ', 'テーリー', 'テーリー', 'コディ', 'ケラプス', 'アサール・ゴッツ'].freeze].freeze
  298. 1 def use_mohumohu_chart(command)
  299. 6 when: 1 else: 0 case command
  300. 1 when: 1 when 'MMI' then use_6x6_chart(MOHUMOHU_INSECT_CHART, 'もふもふ表・昆虫')
  301. 1 when 'MMA' then use_6x6_chart(MOHUMOHU_ANIMAL_CHART, 'もふもふ表・動物')
  302. when: 3 when /MMV[VA]?/
  303. 3 match_data = command.match(/MMV([VA]?)/)
  304. 3 then: 1 else: 2 chart_symbol = match_data[1] == '' ? 'V' : match_data[1]
  305. 3 else: 0 case chart_symbol
  306. when: 2 when 'V'
  307. 2 y_roll = @randomizer.roll_once(D6)
  308. 2 cell_text, x_roll = get_table_by_1d6(MOHUMOHU_VILLACIEL_CHART[1 - y_roll % 2])
  309. 2 when: 1 then: 1 else: 1 "もふもふ表・ヴィラシエル種(ヴィラシエル) > [#{y_roll},#{x_roll}] > 下#{y_roll.even? ? '偶数' : '奇数'}、右#{x_roll}マス > #{cell_text}"
  310. 1 when 'A' then use_6x6_chart(MOHUMOHU_VILLACIEL2_CHART, 'もふもふ表・ヴィラシエル種(アルメサール)')
  311. when: 1 end
  312. 1 when 'MMD' then use_6x6_chart(MOHUMOHU_DRAGON_CHART, 'もふもふ表・鋼龍種')
  313. end
  314. end
  315. 1 FISHING_LAKE_CHART = [['ヤマアイズリ', 'ヤマアイズリ', 'ヤマアイズリ', 'シコウチャ', 'シコウチャ', 'ハナロクショウ'].freeze,
  316. ['ヤマアイズリ', 'ヤマアイズリ', 'ヤマアイズリ', 'シコウチャ', 'ハナロクショウ', 'ハナロクショウ'].freeze,
  317. ['ヤマアイズリ', 'ヤマアイズリ', 'シコウチャ', 'シコウチャ', 'ハナモエギ', 'トノチャ'].freeze,
  318. ['ヤマアイズリ', 'カラスアゲハ', 'シコウチャ', 'ハナロクショウ', 'トノチャ', 'ハナモエギ'].freeze,
  319. ['シコウチャ', 'シコウチャ', 'ハナロクショウ', 'ハナロクショウ', 'トノチャ', 'ハナモエギ'].freeze,
  320. ['シコウチャ', 'ハナロクショウ', 'トノチャ', 'トノチャ', 'ハナモエギ', 'シンペキ'].freeze].freeze
  321. 1 FISHING_RIVER_CHART = [['ケイカンセキ', 'ケイカンセキ', 'ケイカンセキ', 'ケイカンセキ', 'カナリア', 'イワヌ'].freeze,
  322. ['ケイカンセキ', 'ケイカンセキ', 'カナリア', 'カナリア', 'カナリア', 'イワヌ'].freeze,
  323. ['ケイカンセキ', 'ケイカンセキ', 'カナリア', 'イワヌ', 'イワヌ', 'ヤマブキ'].freeze,
  324. ['ケイカンセキ', 'カナリア', 'イワヌ', 'アメイロ', 'アメイロ', 'ヤマブキ'].freeze,
  325. ['カナリア', 'カナリア', 'イワヌ', 'アメイロ', 'ヤマブキ', 'ヤマブキ'].freeze,
  326. ['カナリア', 'イワヌ', 'アメイロ', 'アメイロ', 'ヤマブキ', 'コハク'].freeze].freeze
  327. 1 FISHING_WHITE_CHART = [['ウメガサネ', 'ウメガサネ', 'ウメガサネ', 'ウメガサネ', 'ハネズ', 'ユルシ'].freeze,
  328. ['ウメガサネ', 'ウメガサネ', 'ウメガサネ', 'ハネズ', 'ソホ', 'シンク'].freeze,
  329. ['ウメガサネ', 'ウメガサネ', 'ハネズ', 'ソホ', 'ユルシ', 'ユルシ'].freeze,
  330. ['ウメガサネ', 'ハネズ', 'ソホ', 'ユルシ', 'シンク', 'シンク'].freeze,
  331. ['ハネズ', 'ソホ', 'ソホ', 'ユルシ', 'シンク', '共通(FC)'].freeze,
  332. ['ハネズ', 'ソホ', 'ユルシ', 'シンク', '共通(FC)', 'シュアン'].freeze].freeze
  333. 1 FISHING_GRAY_CHART = [['ウメガサネ', 'ウメガサネ', 'セイラン', 'セイラン', 'ミハナダ', 'ミハナダ'].freeze,
  334. ['ウメガサネ', 'セイラン', 'セイラン', 'ミハナダ', 'ミハナダ', 'ミハナダ'].freeze,
  335. ['ウメガサネ', 'ユルシ', 'ミハナダ', 'ミハナダ', 'ミハナダ', 'リンドウ'].freeze,
  336. ['ユルシ', 'ユルシ', 'セイラン', 'リンドウ', 'リンドウ', 'スミレ'].freeze,
  337. ['ユルシ', 'ユルシ', 'リンドウ', 'スミレ', 'スミレ', '共通(FC)'].freeze,
  338. ['ユルシ', 'リンドウ', 'スミレ', 'スミレ', '共通(FC)', 'シゴク'].freeze].freeze
  339. 1 FISHING_BLACK_CHART = [['セイラン', 'セイラン', 'テツコン', 'テツコン', 'ウスハナ', 'ウスハナ'].freeze,
  340. ['セイラン', 'セイラン', 'テツコン', 'ウスハナ', 'ウスハナ', 'フカガワネズミ'].freeze,
  341. ['セイラン', 'テツコン', 'ウスハナ', 'ウスハナ', 'ミハナダ', 'フカガワネズミ'].freeze,
  342. ['セイラン', 'テツコン', 'ミハナダ', 'ウスハナ', 'フカガワネズミ', 'フカガワネズミ'].freeze,
  343. ['セイラン', 'ウスハナ', 'ミハナダ', 'ミハナダ', 'ミハナダ', '共通(FC)'].freeze,
  344. ['テツコン', 'ウスハナ', 'ミハナダ', 'フカガワネズミ', '共通(FC)', 'ルリ'].freeze].freeze
  345. 1 FISHING_COMMON_CHART = [['トビウオ', 'トビウオ', 'トビウオ', 'オオガメ', 'ロブスター', 'オオサンショウウオ'].freeze,
  346. ['トビウオ', 'トビウオ', 'エイ', 'オオガメ', 'クジラ', 'ロブスター'].freeze,
  347. ['トビウオ', 'エイ', 'マグロ', 'マグロ', 'カジキ', 'イタチザメ'].freeze,
  348. ['トビウオ', 'ミズダコ', 'クラゲ', 'マグロ', 'オオクラゲ', 'ハンマーヘッド・シャーク'].freeze,
  349. ['トビウオ', 'エイ', 'オオガメ', 'オオガメ', 'イタチザメ', 'ミズダコ'].freeze,
  350. ['トビウオ', 'クラゲ', 'ロブスター', 'ハンマーヘッド・シャーク', 'ミズダコ', 'ダイオウイカ'].freeze].freeze
  351. 1 FISHING_SALT_LAKE_CHART = [['シラユリ', 'シラユリ', 'シラユリ', 'ゲッパク', 'ゲッパク', 'ゲッパク'].freeze,
  352. ['シラユリ', 'シラユリ', 'シラユリ', 'ゲッパク', 'スズ', 'ナマリ'].freeze,
  353. ['シラユリ', 'ゲッパク', 'ゲッパク', 'スズ', 'ナマリ', 'ナマリ'].freeze,
  354. ['シラユリ', 'シラユリ', 'ナマリ', 'ナマリ', 'ナマリ', 'ナマリ'].freeze,
  355. ['ゲッパク', 'ゲッパク', 'スズ', 'スズ', 'ロイロ', 'ロイロ'].freeze,
  356. ['ナマリ', 'スズ', 'スズ', 'スズ', 'ロイロ', 'クロツルバミ'].freeze].freeze
  357. 1 def use_fishing_chart(command)
  358. 8 when: 1 else: 0 case command
  359. 1 when: 1 when 'FL' then use_6x6_chart(FISHING_LAKE_CHART, '釣り・湖表')
  360. 1 when: 1 when 'FR' then use_6x6_chart(FISHING_RIVER_CHART, '釣り・河表')
  361. 1 when: 1 when 'FW' then use_6x6_chart(FISHING_WHITE_CHART, '釣り・白雲表')
  362. 1 when: 2 when 'FG' then use_6x6_chart(FISHING_GRAY_CHART, '釣り・灰雲表')
  363. 2 when: 1 when 'FB' then use_6x6_chart(FISHING_BLACK_CHART, '釣り・黒雲表')
  364. 1 when: 1 when 'FC' then use_6x6_chart(FISHING_COMMON_CHART, '釣り・共通表')
  365. 1 when 'FS' then use_6x6_chart(FISHING_SALT_LAKE_CHART, '釣り・塩湖表')
  366. end
  367. end
  368. 1 INEDIBLE_PLANT_CHART = [['シュイの花', 'ダデオの花', 'ロキの花', 'シェラの花', 'トトイト', 'ポロネイマ'].freeze,
  369. ['シュイの花', 'ロキの花', 'アウディの花', 'イディウの花', 'トトイト', 'ポロネイマ'].freeze,
  370. ['ダデオの花', 'アウディの花', 'イディウの花', 'マトイト', 'ポポトマ', 'ルタタ'].freeze,
  371. ['シュイの花', 'ミカギの花', 'ロトイト', 'ロトイト', 'ツルイド', 'ルタタ'].freeze,
  372. ['ミカギの花', 'ロトイト', 'ロトイト', 'ツルイド', 'ルタタ', '変異植物(MP)'].freeze,
  373. ['トトイト', 'マトイト', 'ポポトマ', 'ツルイド', '変異植物(MP)', 'サボサボ'].freeze].freeze
  374. 1 INEDIBLE_PLANT2_CHART = [['マトラの花', 'マトラの花', '蜜蝋', 'ポルラの花', 'ウェスドの花', 'ポルラの花'].freeze,
  375. ['マトラの花', 'ホイの花', 'マトラの花', 'ウェスドの花', '蜜蝋', 'ロロの花'].freeze,
  376. ['ホイの花', 'ポルラの花', 'ウェスドの花', 'ホイの花', 'ポルラの花', 'ポルラの花'].freeze,
  377. ['ポルラの花', 'ホイの花', 'ロロの花', 'ウェスドの花', 'ポルラの花', 'ドダの実'].freeze,
  378. ['ポルラの花', 'ウェスドの花', 'ロロの花', 'ロロの花', 'ロロの花', 'ロロの花'].freeze,
  379. ['ウェスドの花', 'ロロの花', 'ポルラの花', 'ロロの花', 'ドダの実', 'ロロの花'].freeze].freeze
  380. 1 def use_inedible_plant_chart(command)
  381. 4 match_data = command.match(/IP([VA]?)/)
  382. 4 then: 1 else: 3 chart_symbol = match_data[1] == '' ? 'V' : match_data[1]
  383. 4 when: 3 else: 0 case chart_symbol
  384. 3 when: 1 when 'V' then use_6x6_chart(INEDIBLE_PLANT_CHART, '不食植物表(ヴィラシエル)')
  385. 1 when 'A' then use_6x6_chart(INEDIBLE_PLANT2_CHART, '不食植物表(アルメサール)')
  386. end
  387. end
  388. 1 EDIBLE_PLANT_CHARTS = [[['小麦', '小麦', 'さつまいも', 'ねぎ', '白菜', 'きゅうり'].freeze,
  389. ['小麦', 'さつまいも', 'さといも', '白菜', '白菜', 'とうもろこし'].freeze,
  390. ['さといも', 'さといも', 'ねぎ', '白菜', 'とうもろこし', '枝豆'].freeze,
  391. ['シソ', 'ひらたけ', 'エリンギ', '枝豆', '枝豆', 'ラズベリー'].freeze,
  392. ['シソ', 'ひらたけ', 'ひらたけ', 'エリンギ', 'ラズベリー', 'さといも'].freeze,
  393. ['ナシ', 'ナシ', 'ナシ', 'ラズベリー', 'ラズベリー', 'さといも'].freeze].freeze,
  394. [['米', '米', 'にんじん', 'じゃがいも', 'ふき', 'まいたけ'].freeze,
  395. ['米', 'じゃがいも', 'じゃがいも', 'にら', 'ふき', 'きくらげ'].freeze,
  396. ['冬瓜', 'しょうが', '冬瓜', 'ふき', 'ふき', 'きくらげ'].freeze,
  397. ['しょうが', '冬瓜', 'ビワ', 'にら', 'まいたけ', 'まいたけ'].freeze,
  398. ['ビワ', 'ビワ', 'もも', 'かぼちゃ', 'グリーンピース', 'まいたけ'].freeze,
  399. ['ビワ', 'もも', 'もも', 'かぼちゃ', 'かぼちゃ', 'かぼちゃ'].freeze].freeze,
  400. [['もち米', 'トマト', 'オクラ', 'とうがらし', '大根', 'グミ'].freeze,
  401. ['もち米', 'オクラ', 'オクラ', '大根', '大根', 'とうがらし'].freeze,
  402. ['しいたけ', 'マッシュルーム', 'オクラ', 'グミ', '玉ねぎ', '小松菜'].freeze,
  403. ['ブロッコリー', 'しいたけ', 'トマト', '玉ねぎ', 'さやえんどう', '玉ねぎ'].freeze,
  404. ['しいたけ', 'マッシュルーム', 'ブロッコリー', '小松菜', 'さやえんどう', '改良種(IS)'].freeze,
  405. ['マッシュルーム', 'ブロッコリー', 'マッシュルーム', '小松菜', '改良種(IS)', 'グミ'].freeze].freeze,
  406. [['大豆', '大豆', 'にんにく', 'そらまめ', 'しめじ', 'みかん'].freeze,
  407. ['かぶ', '大豆', 'かぶ', 'キャベツ', 'そらまめ', 'みかん'].freeze,
  408. ['にんにく', 'かぶ', 'にんにく', 'しめじ', 'クランベリー', 'ピーマン'].freeze,
  409. ['キャベツ', 'キャベツ', 'ほうれん草', 'しめじ', 'レタス', 'ピーマン'].freeze,
  410. ['ほうれん草', 'ほうれん草', 'クランベリー', 'レタス', 'ピーマン', '改良種(IS)'].freeze,
  411. ['松茸', 'ほうれん草', '松茸', 'レタス', 'クランベリー', '改良種(IS)'].freeze].freeze,
  412. [['小豆', 'れんこん', 'みつば', 'やまのいも', 'デコポン', 'イチゴ'].freeze,
  413. ['れんこん', 'れんこん', '小豆', 'なめこ', 'かいわれ大根', 'なめこ'].freeze,
  414. ['やまのいも', 'アスパラガス', 'なす', 'なめこ', 'やまのいも', 'デコポン'].freeze,
  415. ['なす', 'やまのいも', 'みつば', 'えのきたけ', 'かいわれ大根', 'デコポン'].freeze,
  416. ['アスパラガス', 'アスパラガス', 'やまのいも', 'みつば', 'なめこ', '改良種(IS)'].freeze,
  417. ['なす', 'もやし', 'えのきたけ', 'えのきたけ', '改良種(IS)', 'イチゴ'].freeze].freeze].freeze
  418. 1 EDIBLE_PLANT2_CHARTS = [[['テンサイ', 'バノ', 'テンサイ', 'サトウモロ', 'サトウモロ', 'パンノミ'].freeze,
  419. ['テンサイ', 'バノ', 'サトウモロ', 'バノ', 'ミソレグア', 'パンノミ'].freeze,
  420. ['テンサイ', 'サトウモロ', 'バノ', 'ニクニク', 'パンノミ', 'メーズム'].freeze,
  421. ['バノ', 'バノ', 'バノ', 'パンノミ', 'ミソレグア', 'メーズム'].freeze,
  422. ['テンサイ', 'パンノミ', 'ニクニク', 'ニクニク', 'メーズム', 'ミソレグア'].freeze,
  423. ['サトウモロ', 'ニクニク', 'メーズム', 'ミソレグア', 'メーズム', 'メーズム'].freeze].freeze,
  424. [['アロアベリー', 'パンノミ', 'ミソレグア', 'サイングア', 'パンノミ', 'アロアベリー'].freeze,
  425. ['パンノミ', 'サイングア', 'パンノミ', 'ミソレグア', 'アロアベリー', 'ミソレグア'].freeze,
  426. ['パンノミ', 'アロアベリー', 'サイングア', 'パンノミ', 'パンノミ', 'トロアベリア'].freeze,
  427. ['パンノミ', 'アロアベリー', 'パンノミ', 'ミソレグア', 'ミソレグア', 'トロアベリア'].freeze,
  428. ['サイングア', 'パンノミ', 'トロアベリア', 'ミソレグア', 'アロアベリー', 'サイングア'].freeze,
  429. ['ミソレグア', 'トロアベリア', 'サイングア', 'アロアベリー', 'トロアベリア', 'トロアベリア'].freeze].freeze].freeze
  430. 1 def use_villaciel_edible_plant_chart(chart_id, output)
  431. 4 output + use_6x6_chart(EDIBLE_PLANT_CHARTS[chart_id - 1], "可食植物表#{chart_id}(ヴィラシエル)")
  432. end
  433. 1 def use_armesear_edible_plant_chart(chart_id, output)
  434. 2 output + use_6x6_chart(EDIBLE_PLANT2_CHARTS[chart_id - 1], "可食植物表#{chart_id}(アルメサール)")
  435. end
  436. 1 def use_edible_plant_chart(command)
  437. 11 match_data = command.match(/EP([VA]?)(\d?)/)
  438. 11 then: 3 else: 8 chart_symbol = match_data[1] == '' ? 'V' : match_data[1]
  439. 11 else: 0 case chart_symbol
  440. when: 7 when 'V'
  441. 7 case match_data[2]
  442. when: 2 when ''
  443. 2 roll_result = @randomizer.roll_once(D6)
  444. 2 then: 1 else: 1 return '(1D6) > [6] > 好きな表を選んでおっけー!' if roll_result == D6
  445. 1 use_villaciel_edible_plant_chart(roll_result, "(1D6) > [#{roll_result}] > ")
  446. else: 5 else
  447. 5 chart_id = match_data[2].to_i
  448. 5 else: 3 then: 2 return '' unless chart_id >= 1 && chart_id <= 5
  449. 3 use_villaciel_edible_plant_chart(chart_id, '')
  450. end
  451. when: 4 when 'A'
  452. 4 case match_data[2]
  453. when: 1 when ''
  454. 1 roll_result = @randomizer.roll_once(D6)
  455. 1 then: 1 else: 0 use_armesear_edible_plant_chart(roll_result.even? ? 1 : 2, "(1D6) > [#{roll_result}] > ")
  456. else: 3 else
  457. 3 chart_id = match_data[2].to_i
  458. 3 else: 1 then: 2 return '' unless [1, 2].include?(chart_id)
  459. 1 use_armesear_edible_plant_chart(chart_id, '')
  460. end
  461. end
  462. end
  463. 1 MUTANT_PLANT_CHART = [['ガドゴン', 'ガドゴン', 'レディダン', 'ボディア', 'ブタマル', 'ブタマル'].freeze,
  464. ['レディダン', 'レディダン', 'ボディア', 'トロコッコ', 'ブタマル', 'ツァイド'].freeze,
  465. ['ボディア', 'ボディア', 'マメノキ', 'ナッキュ', 'ツァイド', 'ボディア'].freeze,
  466. ['ナッキュ', 'マメノキ', 'ナッキュ', 'ガドゴン', 'レディダン', 'レディダン'].freeze,
  467. ['ポメラマ', 'ポメラマ', 'ナッキュ', 'ツァイド', 'ガドゴン', 'ボディア'].freeze,
  468. ['ナッキュ', 'ツァイド', 'ツァイド', 'ツァイド', 'ボディア', 'グラディエゴ'].freeze].freeze
  469. 1 def use_mutant_plant_chart(_command)
  470. 1 use_6x6_chart(MUTANT_PLANT_CHART, '変異植物表')
  471. end
  472. 1 IMPROVED_SPECIES_CHART = [['ワワ', 'ワワ', 'ブラックカロット', 'ビーズ', 'レモン', 'ブラッドオレンジ'].freeze,
  473. ['ポポ', 'ポポ', 'グランツェ', 'オオカサゲ', 'ブラッドオレンジ', 'レモン'].freeze,
  474. ['ヒットト', 'グランツェ', 'ブラックベリー', 'ピマット', 'ブラッドオレンジ', 'レモン'].freeze,
  475. ['ブルーベリー', 'ヒットト', 'グランツェ', 'ブラッドオレンジ', 'ユズ', 'ブラックベリー'].freeze,
  476. ['ビーズ', 'ピマット', 'オオカサゲ', 'ライム', 'ブルーベリー', 'ユズ'].freeze,
  477. ['ビーズ', 'レッドキャベツ', 'ライム', 'オオカサゲ', 'ライム', 'リンゴ'].freeze].freeze
  478. 1 def use_improved_species_chart(_command)
  479. 1 use_6x6_chart(IMPROVED_SPECIES_CHART, '改良種表')
  480. end
  481. end
  482. end
  483. end

lib/bcdice/game_system/VisionConnect.rb

100.0% lines covered

100.0% branches covered

50 relevant lines. 50 lines covered and 0 lines missed.
16 total branches, 16 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/command/parser'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class VisionConnect < Base
  6. # ゲームシステムの識別子
  7. 1 ID = "VisionConnect"
  8. # ゲームシステム名
  9. 1 NAME = "ヴィジョンコネクト"
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = "ういしよんこねくと"
  12. 1 HELP_MESSAGE = <<~TEXT
  13. ・判定(VC+x@c#f>=y)
  14. !:コマンドの最初に付けると致命的失敗が全てアクシデントになる。
  15. x:修正値。能力値、戦闘値、その他修正値など。省略可。
  16. y:目標値。省略時は決定的成功/致命的失敗のみ表示。
  17. c:クリティカル値。@ごと省略可。省略時は12。
  18. f:ファンブル値。#ごと省略可。省略時は3。
  19. (例)VC+3>=8
  20. VC+7@11>=12
  21. !VC+6-1#4>=10
  22. ・各種表
  23. アクシデント表 AT
  24. トラブル表 TT
  25. TEXT
  26. 1 def eval_game_system_specific_command(command)
  27. 54 return check_action(command) || roll_tables(command, TABLES)
  28. end
  29. 1 def check_action(command)
  30. 54 parser = Command::Parser.new(/!?VC/, round_type: RoundType::FLOOR)
  31. .enable_critical
  32. .enable_fumble
  33. .restrict_cmp_op_to(nil, :>=)
  34. 54 parsed = parser.parse(command)
  35. 54 then: 4 else: 50 return nil if parsed.nil?
  36. 50 stamina_zero = parsed.command[0] == '!'
  37. 50 critical_target = parsed.critical || 12
  38. 50 fumble_target = parsed.fumble || 3
  39. 50 then: 7 else: 43 accident_target = stamina_zero ? fumble_target : 2
  40. 50 dice_arr = @randomizer.roll_barabara(2, 6)
  41. 50 dice_sum = dice_arr.sum
  42. 50 result_sum = dice_sum + parsed.modify_number
  43. 50 is_critical = dice_sum >= critical_target
  44. 50 is_fumble = dice_sum <= fumble_target
  45. 50 is_accident = dice_sum <= accident_target
  46. 50 is_trouble = is_fumble && !is_accident
  47. 50 then: 9 if is_critical
  48. 9 is_success = true
  49. 9 else: 41 result_str = "決定的成功"
  50. 41 then: 8 elsif is_accident
  51. 8 is_success = false
  52. 8 else: 33 result_str = "致命的失敗(アクシデント)"
  53. 33 then: 8 elsif is_trouble
  54. 8 is_success = false
  55. 8 else: 25 result_str = "致命的失敗(トラブル)"
  56. 25 then: 1 elsif parsed.target_number.nil?
  57. 1 else: 24 is_success = nil
  58. 24 then: 12 elsif result_sum >= parsed.target_number
  59. 12 is_success = true
  60. 12 result_str = "成功"
  61. else: 12 else
  62. 12 is_success = false
  63. 12 result_str = "失敗"
  64. end
  65. sequence = [
  66. 50 "(#{parsed.to_s(:after_modify_number)})",
  67. "#{dice_sum}[#{dice_arr.join(',')}]#{Format.modifier(parsed.modify_number)}",
  68. result_sum,
  69. result_str
  70. ].compact
  71. 50 Result.new.tap do |r|
  72. 50 r.text = sequence.join(" > ")
  73. 50 r.critical = is_critical
  74. 50 r.fumble = is_fumble
  75. 50 r.success = is_success || false
  76. 50 then: 1 else: 49 r.failure = is_success.nil? ? false : !is_success
  77. end
  78. end
  79. TABLES = {
  80. 1 'AT' => DiceTable::Table.new(
  81. 'アクシデント表',
  82. '1D6',
  83. [
  84. '頭がぼんやりして、まぶたが重くなってきた……。これは睡魔の襲来? キャラクターの操作がおぼつかなくなる。シーン終了まで能力値判定、戦闘値判定の達成値に-3される。スタミナを3点消費することで、この効果を打ち消すことができる。',
  85. 'キーボード、マウス、ゲームパッドなどが操作不能になった! キャラクターを操作することができない。戦闘中の場合は次のラウンドの準備プロセス終了までキャラクターアクションを行うことができず、スキルや特技の使用もできない。スタミナを3点消費することで、この効果を打ち消すことができる。',
  86. '急に画面が真っ暗に! パソコンやゲーム機を見ると、動作はしている。これはモニタの問題かっ! キャラクターを操作することができない。戦闘中の場合は次のラウンドの終了までキャラクターアクションを行うことができず、スキル、特技の使用もできない。スタミナを4点消費することで、この効果を打ち消すことができる。',
  87. '突然、通信回線が不調となり、切断されてしまった! 急いで再ログインしなければ! シーンから自動的に退場となる。戦闘中の場合は次のラウンドの準備プロセス終了後、登場できる。スタミナを4点消費することで、この効果を打ち消すことができる。',
  88. 'いきなり画面が真っ黒になり、パソコンやゲーム機が再起動し始めた……。シーンから自動的に退場となる。戦闘中の場合は次のラウンドの終了後、登場できる。スタミナを5点消費することで、この効果を打ち消すことができる。',
  89. '突然、画面が消えた。いや、画面だけじゃない。電化製品がすべて止まっているようだ。もしや、これは停電!? シーンから自動的に退場となる。次のシーンの開始時に登場できる。スタミナを5点消費することで、この効果を打ち消すことができる。',
  90. ]
  91. ),
  92. 'TT' => DiceTable::D66RangeTable.new(
  93. 'トラブル表',
  94. {
  95. 11..13 => 'チャットで誤爆(発言ミス)をしてしまった。恥ずかしさで、スタミナが1点減少する。',
  96. 14..16 => 'かまってほしいのか、ペットがちょっとした悪戯をしてきた。ごめん、今は忙しいのだ。ペットを取得していない場合は何も起こらない。ペットを取得していた場合、罪悪感によりスタミナが1点減少する。',
  97. 21..23 => '何かの用事があるのか、それとも食事の時間なのか、家族から声を掛けられた。家族を取得していない場合は何も起こらない。家族を取得していた場合、気が焦ってスタミナが2点減少する。',
  98. 24..26 => '玄関のチャイムが鳴り、「宅配便でーす」の声が外から聞こえてきた。こんな時にっ!? 家族がいれば、荷物を受け取ってもらえるのだが……。家族を取得している場合は何も起こらない。家族を取得していない場合、スタミナが2点減少する。',
  99. 31..33 => '操作中に勢い余って腕が飲み物に当たってしまい、中身がこぼれてしまった。あとで掃除しないと……。ドリンクを取得していない、あるいはすべて使用済みである場合は何も起こらない。ドリンクを1個失う。',
  100. 34..36 => 'キーボードやゲームパッドの調子があまりよくない。やっぱり、ゲーミングデバイスに買い換えた方がいいか……。デバイスを取得している場合は何も起こらない。デバイスを取得していない場合、ストレスによりスタミナが2点減少する。',
  101. 41..43 => '知り合いから電話が掛かってきた。電話しながらの操作はちょっと大変だ。より集中しなければならないため、スタミナが2点減少する。',
  102. 44..46 => '急にお手洗いに行きたくなってきた。ちょっと我慢しなければならないため、スタミナが2点減少する。',
  103. 51..51 => 'レアモンスターがポップ(出現)したとチャットで通知が来た! でも、今は行くことができない……。ブレイブを取得していない場合は何も起こらない。ブレイブを取得している場合、悔しさでスタミナが3点減少する。',
  104. 52..52 => '出品しているアイテムのマーケットでの相場が下がったと知り合いからチャットが飛んできた。マイスターを取得していない場合は何も起こらない。マイスターを取得している場合、悲しさでスタミナが3点減少する。',
  105. 53..53 => '操作の方法が分からなくなって、焦りまくる。ノービスを取得していない場合は何も起こらない。ノービスを取得している場合、混乱でスタミナが3点減少する。',
  106. 54..54 => 'ギルドのメンバーからギルドを抜けたいという相談のチャットが飛んできた。リーダーを取得していない場合は何も起こらない。リーダーを取得している場合、驚きのあまりスタミナが3点減少する。',
  107. 55..55 => '知り合いから攻略の手伝いを頼むチャットが飛んできた。ごめんなさい、今はちょっと無理……。ヘルパーを取得していない場合は何も起こらない。ヘルパーを取得している場合、申し訳なさでスタミナが3点減少する。',
  108. 56..56 => 'つきまとってくるユーザーから、しつこくチャットが飛んでくる。面倒くさいなぁ。フェイバリットを取得していない場合は何も起こらない。フェイバリットを取得している場合、煩わしさでスタミナが3点減少する。',
  109. 61..61 => '誰かと一緒にプレイするのに慣れていないためか、ちょっと緊張しているかもしれない。ローンウルフを取得していない場合は何も起こらない。ローンウルフを取得している場合、緊張でスタミナが3点減少する。',
  110. 62..62 => '事前に入手していた情報が間違っていた!? どう対応してよいか分からず、焦りまくる。ブレインを取得していない場合は何も起こらない。ブレインを取得している場合、焦りのあまりスタミナが3点減少する。',
  111. 63..63 => '配信でトラブルが発生!? 対応に慌ててしまう。ストリーマーを取得していない場合は何も起こらない。ストリーマーを取得している場合、狼狽によってスタミナが3点減少する。',
  112. 64..64 => '使っているゲーミングデバイスの調子がよくない。ガジェッターを取得していない場合は何も起こらない。ガジェッターを取得している場合、いらだちでスタミナが3点減少する。',
  113. 65..65 => '合間にプレイしている別のゲームや流し見していた動画に注意が向いて、操作をミスしてしまう。カジュアルを取得していない場合は何も起こらない。カジュアルを取得している場合、後悔でスタミナが3点減少する。',
  114. 66..66 => 'ハードコアを取得していない場合は何も起こらない。トラブル表の51~65の項目の効果を受ける。ハードコア以外に取得しているスタイルに合わせて、効果を適用すること(たとえば、ブレイブならば51、マイスターなら52となる)。',
  115. }
  116. ),
  117. }.freeze
  118. 1 register_prefix('!?VC', TABLES.keys)
  119. end
  120. end
  121. end

lib/bcdice/game_system/WARPS.rb

94.44% lines covered

90.0% branches covered

18 relevant lines. 17 lines covered and 1 lines missed.
10 total branches, 9 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class WARPS < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'WARPS'
  7. # ゲームシステム名
  8. 1 NAME = 'ワープス'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'わあふす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = "失敗、成功度の自動判定を行います。\n"
  13. 1 def result_2d6(total, dice_total, _dice_list, cmp_op, target)
  14. 31 else: 30 then: 1 return nil unless cmp_op == :<=
  15. 30 then: 1 if dice_total <= 2
  16. 1 else: 29 Result.critical("クリティカル")
  17. 29 then: 2 elsif dice_total >= 12
  18. 2 else: 27 Result.fumble("ファンブル")
  19. 27 then: 0 elsif target == "?"
  20. else: 27 Result.nothing
  21. 27 then: 15 elsif total <= target
  22. 15 Result.success("#{target - total}成功")
  23. else: 12 else
  24. 12 Result.failure("失敗")
  25. end
  26. end
  27. end
  28. end
  29. end

lib/bcdice/game_system/WaresBlade.rb

100.0% lines covered

83.33% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
6 total branches, 5 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class WaresBlade < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'WaresBlade'
  7. # ゲームシステム名
  8. 1 NAME = 'ワースブレイド'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'わあすふれいと'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = "nD10>=m 方式の判定で成否、完全成功、完全失敗を自動判定します。\n"
  13. 1 def result_nd10(_total, _dice_total, dice_list, cmp_op, _target)
  14. 8 else: 8 then: 0 return nil unless cmp_op == :>=
  15. 8 then: 2 if dice_list.count(10) == dice_list.size
  16. 2 else: 6 Result.critical("完全成功")
  17. 6 then: 2 else: 4 elsif dice_list.count(1) == dice_list.size
  18. 2 Result.fumble("絶対失敗")
  19. end
  20. end
  21. end
  22. end
  23. end

lib/bcdice/game_system/Warhammer.rb

95.76% lines covered

79.59% branches covered

118 relevant lines. 113 lines covered and 5 lines missed.
49 total branches, 39 branches covered and 10 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Warhammer < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Warhammer'
  7. # ゲームシステム名
  8. 1 NAME = 'ウォーハンマー'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'うおおはんまあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・クリティカル表(whHxx/whAxx/whBxx/whLxx)
  14.  "WH部位 クリティカル値"の形で指定します。部位は「H(頭部)」「A(腕)」「B(胴体)」「L(足)」の4カ所です。
  15.  例)whH10 whA5 WHL4
  16. ・命中判定(WHx@t)
  17.  "WH(命中値)@(種別)"の形で指定します。
  18.  種別は脚の数を数字、翼が付いているものは「W」、手が付いているものは「H」で書きます。
  19.  「2H(二足)」「2W(有翼二足)」「4(四足)」「4H(半人四足)」「4W(有翼四足)」「W(鳥類)」となります。
  20.  命中判定を行って、当たれば部位も表示します。
  21.  なお、種別指定を省略すると「二足」、「@」だけにすると全種別の命中部位を表示します。(コマンドを忘れた時の対応です)
  22.  例)wh60  wh43@4W  WH65@
  23. INFO_MESSAGE_TEXT
  24. 1 register_prefix('WH')
  25. 1 def initialize(command)
  26. 241 super(command)
  27. 241 @round_type = RoundType::CEIL # 端数切り上げに設定
  28. end
  29. 1 def eval_game_system_specific_command(command)
  30. 210 output_msg = nil
  31. 210 else: 0 case command.upcase
  32. when: 140 when /^(WH\d+(@[\dWH]*)?)/i
  33. 140 attackCommand = Regexp.last_match(1)
  34. 140 output_msg = getAttackResult(attackCommand)
  35. when: 70 when /^(WH[HABTLW]\d+)/i
  36. 70 criticalCommand = Regexp.last_match(1)
  37. 70 output_msg = getCriticalResult(criticalCommand)
  38. end
  39. 210 return output_msg
  40. end
  41. 1 def result_1d100(total, _dice_total, cmp_op, target)
  42. 171 then: 1 else: 170 return Result.nothing if target == '?'
  43. 170 else: 170 then: 0 return nil unless cmp_op == :<=
  44. 170 then: 77 if total <= target
  45. 77 Result.success("成功(成功度#{(target - total) / 10})")
  46. else: 93 else
  47. 93 Result.failure("失敗(失敗度#{(total - target) / 10})")
  48. end
  49. end
  50. 1 def result_1d100_text(total, dice_total, cmp_op, target)
  51. 140 then: 140 else: 0 result = result_1d100(total, dice_total, cmp_op, target)&.text
  52. 140 then: 0 if result.nil?
  53. ""
  54. else: 140 else
  55. 140 " > #{result}"
  56. end
  57. end
  58. #################### WHFRP関連 ########################
  59. 1 def getCriticalResult(string)
  60. # クリティカル効果データ
  61. 70 whh = [
  62. '01:打撃で状況が把握出来なくなる。次ターンは1回の半アクションしか行なえない。',
  63. '02:耳を強打された為、耳鳴りが酷く目眩がする。1Rに渡って一切のアクションを行なえない。',
  64. '03:打撃が頭皮を酷く傷つけた。【武器技術度】に-10%。治療を受けるまで継続。',
  65. '04:鎧が損傷し当該部位のAP-1。修理するには(職能:鎧鍛冶)テスト。鎧を着けていないなら1Rの間アクションを行なえない。',
  66. '05:転んで倒れ、頭がくらくらする。1Rに渡ってあらゆるテストに-30で、立ち上がるには起立アクションが必要。',
  67. '06:1d10R気絶。',
  68. '07:1d10分気絶。以後CTはサドンデス。',
  69. '08:顔がずたずたになって倒れ、以後無防備状態。治療を受けるまで毎Rの被害者のターン開始時に20%で死亡。以後CTはサドンデスを適用。【頑強】テストに失敗すると片方の視力を失う。',
  70. '09:凄まじい打撃により頭蓋骨が粉砕される。死は瞬時に訪れる。',
  71. '10:死亡する。いかに盛大に出血し、どのような死に様を見せたのかを説明してもよい。',
  72. ]
  73. 70 wha = [
  74. '01:手に握っていたものを落とす。盾はくくりつけられている為、影響なし。',
  75. '02:打撃で腕が痺れ、1Rの間使えなくなる。',
  76. '03:手の機能が失われ、治療を受けるまで回復できない。手で握っていたもの(盾を除く)は落ちる。',
  77. '04:鎧が損傷する。当該部位のAP-1。修理するには(職能:鎧鍛冶)テスト。鎧を着けていないなら腕が痺れ、1Rの間使えなくなる。',
  78. '05:腕の機能が失われ、治療を受けるまで回復できない。手で握っていたもの(盾を除く)は落ちる。',
  79. '06:腕が砕かれる。手で握っていたもの(盾を除く)は落ちる。出血がひどく、治療を受けるまで毎Rの被害者のターン開始時に20%で死亡。以後CTはサドンデスを適用。',
  80. '07:手首から先が血まみれの残骸と化す。手で握っていたもの(盾を除く)は落ちる。出血がひどく、治療を受けるまで毎Rの被害者のターン開始時に20%で死亡。以後CTはサドンデスを適用。【頑健】テストに失敗すると手の機能を失う。',
  81. '08:腕は血まみれの肉塊がぶら下がっている状態になる。手で握っていたもの(盾を除く)は落ちる。治療を受けるまで毎Rの被害者のターン開始時に20%で死亡。以後CTはサドンデスを適用。【頑健】テストに失敗すると肘から先の機能を失う。',
  82. '09:大動脈に傷が及んだ。コンマ数秒の内に損傷した肩から血を噴出して倒れる。ショックと失血により、ほぼ即死する。',
  83. '10:死亡する。いかに盛大に出血し、どのような死に様を見せたのかを説明してもよい。',
  84. ]
  85. 70 whb = [
  86. '01:打撃で息が詰まる。1Rの間、キャラクターの全てのテストや攻撃に-20%。',
  87. '02:股間への一撃。苦痛のあまり、1Rに渡って一切のアクションを行なえない。',
  88. '03:打撃で肋骨がぐちゃぐちゃになる。以後治療を受けるまでの間、【武器技術度】に-10%。',
  89. '04:鎧が損傷する。当該部位のAP-1。修理するには(職能:鎧鍛冶)テスト。鎧を着けていないなら股間への一撃、1Rに渡って一切のアクションを行なえない。',
  90. '05:転んで倒れ、息が詰まって悶絶する。1Rに渡ってあらゆるテストに-30の修正、立ち上がるには起立アクションが必要。',
  91. '06:1d10R気絶。',
  92. '07:ひどい内出血が起こり、無防備状態。出血がひどく、治療を受けるまで毎Rの被害者のターン開始時に20%で死亡。',
  93. '08:脊髄が粉砕されて倒れ、以後治療を受けるまで無防備状態。以後CTはサドンデスを適用。【頑強】テストに失敗すると腰から下が不随になる。',
  94. '09:凄まじい打撃により複数の臓器が破裂し、死は数秒のうちに訪れる。',
  95. '10:死亡する。いかに盛大に出血し、どのような死に様を見せたのかを説明してもよい。',
  96. ]
  97. 70 whl = [
  98. '01:よろめく。次のターン、1回の半アクションしか行なえない。',
  99. '02:脚が痺れる。1Rに渡って【移動】は半減し、脚に関連する【敏捷】テストに-20%。回避が出来なくなる。',
  100. '03:脚の機能が失われ、治療を受けるまで回復しない。【移動】は半減し、脚に関連する【敏捷】テストに-20%。回避が出来なくなる。',
  101. '04:鎧が損傷する。当該部位のAP-1。修理するには(職能:鎧鍛冶)テスト。鎧を着けていないなら脚が痺れる、1Rに渡って【移動】は半減し、脚に関連する【敏捷】テストに-20%、回避不可になる。',
  102. '05:転んで倒れ、頭がくらくらする。1Rに渡ってあらゆるテストに-30の修正、立ち上がるには起立アクションが必要。',
  103. '06:脚が砕かれ、無防備状態。出血がひどく、治療を受けるまで毎Rの被害者のターン開始時に20%で死亡。以後CTはサドンデスを適用。',
  104. '07:脚は血まみれの残骸と化し、無防備状態になる。治療を受けるまで毎Rの被害者のターン開始時に20%で死亡。以後CTはサドンデスを適用。【頑強】テストに失敗すると足首から先を失う。',
  105. '08:脚は血まみれの肉塊がぶらさがっている状態。以後無防備状態。治療を受けるまで毎Rの被害者のターン開始時に20%で死亡。以後CTはサドンデスを適用。【頑強】テストに失敗すると膝から下を失う。',
  106. '09:大動脈に傷が及ぶ。コンマ数秒の内に脚の残骸から血を噴出して倒れ、ショックと出血で死は瞬時に訪れる。',
  107. '10:死亡する。いかに盛大に出血し、どのような死に様を見せたのかを説明してもよい。',
  108. ]
  109. 70 whw = [
  110. '01:軽打。1ラウンドに渡って、あらゆるテストに-10%。',
  111. '02:かすり傷。+10%の【敏捷】テストを行い、失敗なら直ちに高度を1段階失う。地上にいるクリーチャーは、次のターンには飛び立てない。',
  112. '03:損傷する。【飛行移動力】が2点低下する。-10%の【敏捷】テストを行い、失敗なら直ちに高度を1段階失う。地上にいるクリーチャーは、次のターンには飛び立てない。',
  113. '04:酷く損傷する。【飛行移動力】が4点低下する。-30%の【敏捷】テストを行い、失敗なら直ちに高度を1段階失う。地上にいるクリーチャーは、1d10ターンが経過するまで飛び立てない。',
  114. '05:翼が使えなくなる。【飛行移動力】が0に低下する。飛行中のものは落下し、高度に応じたダメージを受ける。地上にいるクリーチャーは、怪我が癒えるまで飛び立てない。',
  115. '06:翼の付け根に傷が開く。【飛行移動力】が0に低下する。飛行中のものは落下し、高度に応じたダメージを受ける。地上にいるクリーチャーは、怪我が癒えるまで飛び立てない。治療を受けるまで毎R被害者のターン開始時に20%の確率で死亡。以後CTはサドンデスを適用。',
  116. '07:翼は血まみれの残骸と化し、無防備状態になる。【飛行移動力】が0に低下する。飛行中のものは落下し、高度に応じたダメージを受ける。地上にいるクリーチャーは、怪我が癒えるまで飛び立てない。治療を受けるまで毎R被害者のターン開始時に20%の確率で死亡。以後CTはサドンデスを適用。【頑強】テストに失敗すると飛行能力を失う。',
  117. '08:翼が千切れてバラバラになり、無防備状態になる。【飛行移動力】が0に低下する。飛行中のものは落下し、高度に応じたダメージを受ける。地上にいるクリーチャーは、怪我が癒えるまで飛び立てない。治療を受けるまで毎R被害者のターン開始時に20%の確率で死亡。以後CTはサドンデスを適用。飛行能力を失う。',
  118. '09:大動脈が切断された。コンマ数秒の内に血を噴き上げてくずおれる、ショックと出血で死は瞬時に訪れる。',
  119. '10:死亡する。いかに盛大に出血し、どのような死に様を見せたのかを説明してもよい。',
  120. ]
  121. 70 criticalTable = [
  122. 5, 7, 9, 10, 10, 10, 10, 10, 10, 10, # 01-10
  123. 5, 6, 8, 9, 10, 10, 10, 10, 10, 10, # 11-20
  124. 4, 6, 8, 9, 9, 10, 10, 10, 10, 10, # 21-30
  125. 4, 5, 7, 8, 9, 9, 10, 10, 10, 10, # 31-40
  126. 3, 5, 7, 8, 8, 9, 9, 10, 10, 10, # 41-50
  127. 3, 4, 6, 7, 8, 8, 9, 9, 10, 10, # 51-60
  128. 2, 4, 6, 7, 7, 8, 8, 9, 9, 10, # 61-70
  129. 2, 3, 5, 6, 7, 7, 8, 8, 9, 9, # 71-80
  130. 1, 3, 5, 6, 6, 7, 7, 8, 8, 9, # 81-90
  131. 1, 2, 4, 5, 6, 6, 7, 7, 8, 8, # 91-00
  132. ]
  133. 70 else: 70 then: 0 unless /WH([HABTLW])(\d+)/ =~ string
  134. return '1'
  135. end
  136. 70 partsWord = Regexp.last_match(1) # 部位
  137. 70 criticalValue = Regexp.last_match(2).to_i # クリティカル値
  138. 70 then: 0 else: 70 criticalValue = 10 if criticalValue > 10
  139. 70 then: 0 else: 70 criticalValue = 1 if criticalValue < 1
  140. 70 whpp = ''
  141. 70 whppp = ''
  142. 70 else: 0 case partsWord
  143. when: 20 when /H/i
  144. 20 whpp = '頭部'
  145. 20 whppp = whh
  146. when: 20 when /A/i
  147. 20 whpp = '腕部'
  148. 20 whppp = wha
  149. when: 10 when /[TB]/i
  150. 10 whpp = '胴体'
  151. 10 whppp = whb
  152. when: 20 when /L/i
  153. 20 whpp = '脚部'
  154. 20 whppp = whl
  155. when: 0 when /W/i
  156. whpp = '翼部'
  157. whppp = whw
  158. end
  159. 70 dice_now = @randomizer.roll_once(100)
  160. 70 crit_no = ((dice_now - 1) / 10).to_i * 10
  161. 70 crit_num = criticalTable[crit_no + criticalValue - 1]
  162. 70 resultText = whppp[crit_num - 1]
  163. 70 then: 58 if crit_num >= 5
  164. 58 resultText += 'サドンデス×'
  165. else: 12 else
  166. 12 resultText += 'サドンデス○'
  167. end
  168. 70 output = "#{whpp}CT表(#{dice_now}+#{criticalValue}) > #{resultText}"
  169. 70 return output
  170. end
  171. 1 def wh_atpos(pos_num, pos_type) # WHFRP2命中部位表
  172. 63 debug("wh_atpos begin pos_type", pos_type)
  173. 63 pos_2l = [
  174. '二足',
  175. 15, '頭部',
  176. 35, '右腕',
  177. 55, '左腕',
  178. 80, '胴体',
  179. 90, '右脚',
  180. 100, '左脚',
  181. ]
  182. 63 pos_2lw = [
  183. '有翼二足',
  184. 15, '頭部',
  185. 25, '右腕',
  186. 35, '左腕',
  187. 45, '右翼',
  188. 55, '左翼',
  189. 80, '胴体',
  190. 90, '右脚',
  191. 100, '左脚',
  192. ]
  193. 63 pos_4l = [
  194. '四足',
  195. 15, '頭部',
  196. 60, '胴体',
  197. 70, '右前脚',
  198. 80, '左前脚',
  199. 90, '右後脚',
  200. 100, '左後脚',
  201. ]
  202. 63 pos_4la = [
  203. '半人四足',
  204. 10, '頭部',
  205. 20, '右腕',
  206. 30, '左腕',
  207. 60, '胴体',
  208. 70, '右前脚',
  209. 80, '左前脚',
  210. 90, '右後脚',
  211. 100, '左後脚',
  212. ]
  213. 63 pos_4lw = [
  214. '有翼四足',
  215. 10, '頭部',
  216. 20, '右翼',
  217. 30, '左翼',
  218. 60, '胴体',
  219. 70, '右前脚',
  220. 80, '左前脚',
  221. 90, '右後脚',
  222. 100, '左後脚',
  223. ]
  224. 63 pos_b = [
  225. '鳥',
  226. 15, '頭部',
  227. 35, '右翼',
  228. 55, '左翼',
  229. 80, '胴体',
  230. 90, '右脚',
  231. 100, '左脚',
  232. ]
  233. 63 wh_pos = [pos_2l, pos_2lw, pos_4l, pos_4la, pos_4lw, pos_b]
  234. 63 pos_t = 0
  235. 63 debug("pos_type", pos_type)
  236. 63 then: 51 else: 12 if pos_type != ""
  237. 51 case pos_type
  238. when: 4 when /@(2W|W2)/i
  239. 4 pos_t = 1
  240. when: 12 when /@(4W|W4)/i
  241. 12 pos_t = 4
  242. when: 3 when /@(4H|H4)/i
  243. 3 pos_t = 3
  244. when: 3 when /@4/i
  245. 3 pos_t = 2
  246. when: 9 when /@W/i
  247. 9 pos_t = 5
  248. else: 20 else
  249. 20 else: 5 then: 15 unless /@(2H|H2|2)/i =~ pos_type
  250. 15 pos_t = -1
  251. end
  252. end
  253. end
  254. 63 output = ""
  255. 63 debug("pos_t", pos_t)
  256. 63 then: 15 if pos_t < 0
  257. 15 wh_pos.each do |pos_i|
  258. 90 output += get_wh_atpos_message(pos_i, pos_num)
  259. end
  260. else: 48 else
  261. 48 pos_i = wh_pos[pos_t]
  262. 48 output += get_wh_atpos_message(pos_i, pos_num)
  263. end
  264. 63 return output
  265. end
  266. 1 def get_wh_atpos_message(pos_i, pos_num)
  267. 138 output = ""
  268. 138 output += ' ' + pos_i[0] + ":"
  269. 138 1.step(pos_i.length + 1, 2) do |i|
  270. 482 then: 138 else: 344 if pos_num <= pos_i[i]
  271. 138 output += pos_i[i + 1]
  272. 138 break
  273. end
  274. end
  275. 138 return output
  276. end
  277. 1 def getAttackResult(string)
  278. 140 debug("getAttackResult begin string", string)
  279. 140 pos_type = ""
  280. 140 then: 120 else: 20 if /(.+)(@.*)/ =~ string
  281. 120 string = Regexp.last_match(1)
  282. 120 pos_type = Regexp.last_match(2)
  283. 120 debug("pos_type", pos_type)
  284. end
  285. 140 else: 140 then: 0 unless /WH(\d+)/i =~ string
  286. return '1'
  287. end
  288. 140 diff = Regexp.last_match(1).to_i
  289. 140 total_n = @randomizer.roll_once(100)
  290. 140 output = "(#{string}) > #{total_n}"
  291. 140 output += result_1d100_text(total_n, total_n, :<=, diff)
  292. 140 pos_num = (total_n % 10) * 10 + (total_n / 10).to_i
  293. 140 then: 3 else: 137 pos_num = 100 if total_n >= 100
  294. 140 then: 63 else: 77 output += wh_atpos(pos_num, pos_type) if total_n <= diff
  295. 140 return output
  296. end
  297. end
  298. end
  299. end

lib/bcdice/game_system/Warhammer4.rb

96.49% lines covered

88.71% branches covered

114 relevant lines. 110 lines covered and 4 lines missed.
62 total branches, 55 branches covered and 7 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Warhammer4 < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'Warhammer4'
  7. # ゲームシステム名
  8. 1 NAME = 'ウォーハンマーRPG第4版'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'うおおはんまあ4'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ■ クリティカル表 (whctH, whctA, whctB, whctL, whctHU, whctAU, whctBU, whctLU)
  14. "WH部位 頑健ボーナス以下フラグ"の形で指定します。
  15. 部位は「H(頭部)」「A(腕)」「B(胴体)」「L(足)」の4カ所です。
  16. 頑健ボーナスフラグは頑健ボーナス以下のダメージの時にUをつけます。
  17. 例)whctH whctAU WHCTL
  18. ■ 命中部位表 (WHLT)
  19. 命中部位をランダムに決定します。(クリティカル用)
  20. ■ やっちまった!表 (WHFT)
  21. やっちまった!表をロールして、結果を表示します。
  22. ■ 神々の天罰表 (WHWGTx)
  23. "WHWGT(原罪点)"の形で指定します。
  24. 原罪点を省略した場合は、原罪点=0として処理します。
  25. 神々の天罰表をロールして、結果を表示します。
  26. ■ 小誤発動表 (WHMIT)
  27. 小誤発動表をロールして、結果を表示します。
  28. ■ 大誤発動表 (WHMAT)
  29. 大誤発動表をロールして、結果を表示します。
  30. ■ 命中判定 (WHx)
  31. "WH(命中値)"の形で指定します。
  32. 命中判定を行って、クリティカルかファンブルでなければ部位も表示します。
  33. 例)wh60  wh(43-20)
  34. INFO_MESSAGE_TEXT
  35. 1 register_prefix('WH')
  36. 1 def initialize(command)
  37. 228 super(command)
  38. 228 @round_type = RoundType::CEIL
  39. end
  40. 1 def eval_game_system_specific_command(command)
  41. 205 roll_critical_table(command) ||
  42. roll_attack(command) ||
  43. roll_wrath_of_god_table(command) ||
  44. roll_tables(command, TABLES)
  45. end
  46. 1 def result_1d100(total, _dice_total, cmp_op, target)
  47. 33 then: 1 else: 32 return Result.nothing if target == '?'
  48. 32 else: 32 then: 0 return nil unless cmp_op == :<=
  49. 32 t10 = total / 10
  50. 32 d10 = target / 10
  51. 32 sl = d10 - t10
  52. 32 if total <= 5 && sl < 1
  53. then: 1 # 自動成功時のSLは最低でも1
  54. 1 else: 31 sl = 1
  55. 31 else: 30 elsif total >= 96 && sl > -1
  56. then: 1 # 自動失敗時のSLは最大でも-1
  57. 1 sl = -1
  58. end
  59. result =
  60. 32 then: 2 if total <= 5
  61. 2 else: 30 Result.success("自動成功")
  62. 30 then: 3 elsif total >= 96
  63. 3 else: 27 Result.failure("自動失敗")
  64. 27 then: 16 elsif total <= target
  65. 16 Result.success("成功")
  66. else: 11 else
  67. 11 Result.failure("失敗")
  68. end
  69. 32 sl_text = format("(SL%+d)", sl)
  70. 32 then: 1 else: 31 if (sl == 0) && (total > target)
  71. 1 sl_text = "(SL-0)"
  72. end
  73. 32 result.text += "#{sl_text} > #{result_detail(sl, total, target)}"
  74. 32 return result
  75. end
  76. 1 private
  77. 1 def result_detail(sl, total, target)
  78. 32 then: 2 if sl == 0
  79. 2 then: 0 if total <= 5
  80. else: 2 '小成功'
  81. 2 then: 0 elsif total >= 96
  82. else: 2 '小失敗'
  83. 2 then: 1 elsif total <= target
  84. 1 '小成功'
  85. else: 1 else
  86. 1 '小失敗'
  87. else: 30 end
  88. 30 then: 5 elsif sl >= 6
  89. 5 else: 25 '超大成功'
  90. 25 then: 4 elsif sl >= 4
  91. 4 else: 21 '大成功'
  92. 21 then: 5 elsif sl >= 2
  93. 5 else: 16 '成功'
  94. 16 then: 3 elsif sl > 0
  95. 3 else: 13 '小成功'
  96. 13 then: 5 elsif sl >= -1
  97. 5 else: 8 '小失敗'
  98. 8 then: 2 elsif sl >= -3
  99. 2 else: 6 '失敗'
  100. 6 then: 2 elsif sl >= -5
  101. 2 '大失敗'
  102. else: 4 else # sl <= -6
  103. 4 '超大失敗'
  104. end
  105. end
  106. # クリティカル表
  107. 1 def roll_critical_table(command)
  108. 205 m = /^WHCT([HABTL])(U)?$/.match(command)
  109. 205 else: 158 then: 47 return nil unless m
  110. 158 part = m[1]
  111. 158 then: 0 else: 158 part = "B" if part == "T"
  112. 158 under_ganken_bonus = !m[2].nil?
  113. 158 CRITICAL_TABLES[part].roll(@randomizer, under_ganken_bonus)
  114. end
  115. 1 class CriticalTable
  116. 1 def initialize(name, items)
  117. 4 @name = name
  118. 4 @items = items
  119. end
  120. 1 def roll(randomizer, under_ganken_bonus)
  121. 158 dice = randomizer.roll_once(100)
  122. 158 then: 2 else: 156 if under_ganken_bonus
  123. 2 dice = (dice - 20).clamp(1, 100)
  124. end
  125. 1766 chosen = @items.find { |key, _| key >= dice }[1]
  126. 158 "#{@name}(#{dice}) > #{chosen}"
  127. end
  128. end
  129. CRITICAL_TABLES = {
  130. 1 "H" => CriticalTable.new(
  131. "頭部CT表",
  132. [
  133. [10, '勲章となる傷:耐久値-1:「出血状態」1つを得る。社交系テストSL+1(累積なし)。'],
  134. [20, '小さな裂傷:耐久値-1:「出血状態」1つを得る。'],
  135. [25, '眼窩の負傷:耐久値-1:「目がくらんだ状態」1つを得る。'],
  136. [30, '耳朶への強打:耐久値-1:「耳鳴り状態」1つを得る。'],
  137. [35, '朦朧化打撃:耐久値-2:「朦朧状態」1つを得る。'],
  138. [40, '眼の周りの青あざ:耐久値-2:「目がくらんだ状態」2つを得る。'],
  139. [45, '耳朶の裂傷:耐久値-2:「出血状態」2つに加えて、「耳鳴り状態」1つを得る。'],
  140. [50, '額への一打:耐久値-2:「出血状態」2つに加えて「目がくらんだ状態」1つを得る。なお後者は「出血状態」を取り除いた後でなければ取り除けない。'],
  141. [55, '顎骨折:耐久値-3:「朦朧状態」2つを得る。さらに「骨折(軽度)」の負傷を得る。'],
  142. [60, '眼窩の大怪我:耐久値-3:「出血状態」2つを得る。さらに「目がくらんだ状態」1つも得て、こちらは「治療行為」を受けない限り回復できない。'],
  143. [65, '耳朶の大怪我:耐久値-3:片耳の聴力を失う。聴覚に関するテストに-20。この効果をもう一度受けた場合、永続的な聴覚喪失者となる。これは魔法でしか治療できない。'],
  144. [70, '鼻砕き:耐久値-3:「出血状態」2つを得る。「手強い(+0)」〈肉体抵抗〉テストを行い、失敗したら「朦朧状態」1つも得る。社交系テストに+1/-1。'],
  145. [75, '顎粉砕:耐久値-4:「朦朧状態」3つを得る。「手強い(+0)」〈肉体抵抗〉テストを行い、失敗したら「気絶状態」を得る。「骨折(重度)」の負傷を得る。'],
  146. [80, '脳震盪打撃:耐久値-4:「出血状態」2つと「耳鳴り状態」1つに加えて1d10の「朦朧状態」を得る。さらに1d10日間継続する「疲労状態」1つも得る。この「疲労状態」継続中に頭部への「致命的負傷」を再度得たなら、「普通(+20)」の〈肉体抵抗〉テストを行い、失敗したなら追加で「気絶状態」になる。'],
  147. [85, '口粉砕:耐久値-4:「出血状態」2つを得る。1d10本の歯が失われる。「身体欠損(容易)」を被る。'],
  148. [90, '耳が屑肉に:耐久値-4:「耳鳴り状態」3つに加えて「出血状態」2つを得る。片耳の機能を失う。「身体欠損(普通)」を被る。'],
  149. [93, '眼球破裂:耐久値-5:「目がくらんだ状態」3つと、「出血状態」2つ、「朦朧状態」1つを得る。片目の機能を失う。「身体欠損(難しい)」を被る。'],
  150. [96, '顔が化け物のように:耐久値-5:「出血状態」3つ「目がくらんだ状態」3つ、「朦朧状態」2つを得る。片目の機能を失い、鼻梁も失う。「身体欠損(多難)」を被る。'],
  151. [99, '顎が屑肉に:耐久値-5:「出血状態」4つと「朦朧状態」3つを得る。「超多難(-30)」な〈肉体抵抗〉テストを行い、失敗したら「気絶状態」になる。「骨折(重度)」の負傷を得て、舌と1d10本の歯を失う。「身体欠損(多難)」を被る。'],
  152. [100, '斬首刑さながらに:即死:'],
  153. ]
  154. ),
  155. "A" => CriticalTable.new(
  156. "腕部CT表",
  157. [
  158. [10, '腕痺れ:耐久値-1:手に持っているものを落としてしまう。'],
  159. [20, '小さな裂傷:耐久値-1:「出血状態」1つを得る。'],
  160. [25, '捻挫:耐久値-1:「筋断裂(軽度)」の負傷を得る。'],
  161. [30, 'ひどい腕痺れ:耐久値-2:手に持っているものを落としてしまい、その腕は1d10-【頑健力】ボーナスのラウンドに渡って使えなくなる。'],
  162. [35, '筋断裂:耐久値-2:「出血状態」1つと、「筋断裂(軽度)」の負傷を得る。'],
  163. [40, '手の出血:耐久値-2:「出血状態」1つを得る。その手で何かを握る「アクション」を行う場合、先立って「普通(+20)」の【器用度】テストを行い、失敗したら取り落としてしまう。'],
  164. [45, '肩の捻挫:耐久値-2:手に持っているものを落としてしまい、その腕は1d10ラウンドに渡って使えなくなる。'],
  165. [50, '大きな傷口:耐久値-3:「出血状態」2つを得る。傷口を縫う「手術」を受ける前に同じ腕にダメージを受けた場合、傷口が開き「出血状態」1つを追加で得る。'],
  166. [55, '単純骨折:耐久値-3:手に持っているものを落としてしまい、「骨折(軽度)」の負傷を得る。「難しい(-10)」〈肉体抵抗〉テストを行い、失敗したなら「朦朧状態」1つを得る。'],
  167. [60, '靱帯断裂:耐久値-3:手に持っているものを落としてしまい、「筋断裂(重度)」の負傷を得る。'],
  168. [65, '深手:耐久値-3:「出血状態」2つを得る。「朦朧状態」1つを得て、「筋断裂(軽度)」の負傷を得る。「多難(-20)」な〈肉体抵抗〉テストを行い、失敗したなら「気絶状態」になる。'],
  169. [70, '動脈破損:耐久値-4:「出血状態」4つを得る。「手術」を受ける前に同じ腕にダメージを受けるたびに「出血状態」2つを得る。'],
  170. [75, '肘粉砕:耐久値-4:手に持っているものを落としてしまい、「筋断裂(重度)」の負傷を得る。'],
  171. [80, '肩の脱臼:耐久値-4:「多難(-20)」な〈肉体抵抗〉テストを行い、失敗したなら「朦朧状態」1つを得て「伏せ状態」になる。手に持っているものを落としてしまう。その腕を使うことはできず、欠損したものとして扱う。さらに「治療行為」を受けるまでの間「朦朧状態」1つを得る。'],
  172. [85, '指切断:耐久値-4:「身体欠損(普通)」を被る。「出血状態」1つを得る。'],
  173. [90, '手の半切断:耐久値-5:指一本を失い、「身体欠損(多難)」を被る。「出血状態」2つと「朦朧状態」1つを得る。君が「治療行為」を受けるまでの以降の各ラウンドに指を一本ずつ失う。すべての指を失ったら、その手の機能を失い「身体欠損(難しい)」を得る。'],
  174. [93, '力こぶがズタズタに:耐久値-5:手に持っていたものを落とすとともに「筋断裂(重度)」の負傷を得て、「出血状態」2つと「朦朧状態」1つを得る。'],
  175. [96, '片手が屑肉同然に:耐久値-5:その手の機能を失い、「身体欠損(多難)」を被る。「出血状態」2つを得る。「多難(-20)」な〈肉体抵抗〉テストを行い、失敗したなら「気絶状態」になる。'],
  176. [99, '靱帯断裂:耐久値-5:腕は無用の長物と化す―「身体欠損(超多難)」を被る。「出血状態」3つ、「朦朧状態」1つを得て、「伏せ状態」になる。「多難(-20)」な〈肉体抵抗〉テストを行い、失敗したなら「気絶状態」になる。'],
  177. [100, '残酷な腕の喪失:即死:'],
  178. ]
  179. ),
  180. "B" => CriticalTable.new(
  181. "胴体CT表",
  182. [
  183. [10, 'ただのかすり傷だって!:耐久値-1:「出血状態」1つを得る。'],
  184. [20, 'みぞおちへの一打:耐久値-1:「朦朧状態」1つを得る。「容易(+40)」な〈肉体抵抗〉テストを行い、失敗したなら「伏せ状態」になる。'],
  185. [25, '下腹部に直撃!:耐久値-1:「多難(-20)」な〈肉体抵抗〉テストを行い、失敗したなら「朦朧状態」3つを得る。'],
  186. [30, '背中を捻じる:耐久値-1:「筋断裂(軽度)」の負傷を得る。'],
  187. [35, '息ができない:耐久値-2:「朦朧状態」1つを得る。「普通(+20)」の〈肉体抵抗〉テストを行い、失敗したなら「伏せ状態」になる。また、1d10ラウンドに渡って「移動力」が半分になる。'],
  188. [40, '肋骨に青あざ:耐久値-2:1d10日間に渡って【敏捷力】に関連するテストに-10。'],
  189. [45, '鎖骨捻じれ:耐久値-2:左右どちらの鎖骨かランダムに決定する。そちらの手に持っている物を落としてしまい、1d10ラウンドに渡ってその腕は使用できない。'],
  190. [50, '裂傷:耐久値-2:「出血状態」2つを得る。'],
  191. [55, '肋骨にひびが:耐久値-3:「朦朧状態」1つを得る。また、「骨折(軽度)」の負傷を得る。'],
  192. [60, '大きな傷口:耐久値-3:「出血状態」3つを得る。「手術」を受けるまでの間、胴体に命中を受けるたびに追加で1つの「出血状態」を得る。'],
  193. [65, '激痛を伴う裂傷:耐久値-3:「出血状態」2つと「朦朧状態」1つを得る。「多難(-20)」な〈肉体抵抗〉テストを行い、失敗したなら「気絶状態」になる。またSL+4以上でテストに成功していない限り、金切り声を上げてしまう。'],
  194. [70, '動脈損傷:耐久値-3:「出血状態」4つを得る。「手術」を受けるまでの間、胴体に攻撃を受けるたびに追加で2つの「出血状態」を得る。'],
  195. [75, '背筋断裂:耐久値-4:「筋断裂(重度)」の負傷を得る。'],
  196. [80, '股関節骨折:耐久値-4:「朦朧状態」1つを得る。「手強い(+0)」〈肉体抵抗〉テストを行い、失敗したなら「伏せ状態」にもなる。「骨折(軽度)」の負傷を得る。'],
  197. [85, '胸郭の大怪我:耐久値-4:「出血状態」4つを得る。「手術」を受けるまでの間、胴体に命中を受けるたびに追加で2つの「出血状態」を得る。'],
  198. [90, '内臓の損傷:耐久値-4:「膿み傷」に罹患し、「出血状態」2つを得る。'],
  199. [93, '胸郭粉砕:耐久値-5:「朦朧状態」1つを得る。これは「治療行為」を受けない限り取り除くことは出来ない。さらに「骨折(重度)」の負傷を得る。'],
  200. [96, '鎖骨粉砕:耐久値-5:「気絶状態」になる。これは「治療行為」を受けない限り取り除くことは出来ない。さらに「骨折(重度)」の負傷を得る。'],
  201. [99, '内臓出血:耐久値-5:「出血状態」1つを得る。これは「手術」を受けない限り取り除くことは出来ない。さらに「血液腐れ病」に罹患する。'],
  202. [100, '胴部両断:即死:'],
  203. ]
  204. ),
  205. "L" => CriticalTable.new(
  206. "脚部CT表",
  207. [
  208. [10, '爪先をぶつける:耐久値-1:「普通(+20)」の〈肉体抵抗〉テストを行い、失敗したなら次のターンの終了時まで【敏捷力】に関するテストに-10。'],
  209. [20, '足首の捻挫:耐久値-1:以降1d10ラウンドに渡って【敏捷力】に関連するテストに-10。'],
  210. [25, '小さな裂傷:耐久値-1:「出血状態」1つを得る。'],
  211. [30, '足がかりを失う:耐久値-1:「手強い(+0)」〈肉体抵抗〉テストを行い、失敗したなら「伏せ状態」になる。'],
  212. [35, '太腿への打撃:耐久値-2:「出血状態」1つを得て「普通(+20)」の〈肉体抵抗〉テストを行い、失敗したなら「伏せ状態」になる。'],
  213. [40, '足首の筋断裂:耐久値-2:「筋断裂(軽度)」の負傷を得る。'],
  214. [45, '膝の捻挫:耐久値-2:以降1d10ラウンドに渡って【敏捷力】に関連するテストに-20。'],
  215. [50, '爪先のひどい裂傷:耐久値-2:「出血状態」1つを得る。「手強い(+0)」〈肉体抵抗〉テストを行い、失敗したなら片方の爪先を失う―「身体欠損(普通)」を被る。'],
  216. [55, 'ひどい裂傷:耐久値-3:「出血状態」2つを得る。「手強い(+0)」〈肉体抵抗〉テストを行い、失敗したなら「伏せ状態」になる。'],
  217. [60, '膝のひどい捻挫:耐久値-3:「筋断裂(重度)」の負傷を得る。'],
  218. [65, '脚への痛打:耐久値-3:「伏せ状態」に加えて「出血状態」2つを得て、「骨折(軽度)」の負傷を得る。さらに「多難(-20)」な〈肉体抵抗〉テストを行い、失敗したなら「朦朧状態」1つを追加で得る。'],
  219. [70, '太腿への深手:耐久値-3:「出血状態」3つを得る。「手強い(+0)」〈肉体抵抗〉テストを行い、失敗したなら「伏せ状態」になる。「手術」を受けるまでの間、この脚に命中を受けるたびに、追加で1つの「出血状態」を得る。'],
  220. [75, '靱帯断裂:耐久値-4:「伏せ状態」に加えて「朦朧状態」1つを得る。「多難(-20)」な〈肉体抵抗〉テストを行い、失敗したなら「気絶状態」になる。君のその脚は使えなくなる。'],
  221. [80, '脛への深手:耐久値-4:敵の武器が君の膝下に当たり、骨に食い込んで腱を切断する。「朦朧状態」1つを得て、「伏せ状態」になる。さらに「筋断裂(重度)」と「骨折(軽度)」の負傷を得る。'],
  222. [85, '膝粉砕:耐久値-4:「出血状態」1つと「朦朧状態」1つを得ることに加えて、「伏せ状態」になる。「骨折(重度)」の負傷を得る。'],
  223. [90, '膝関節脱臼:耐久値-4:「伏せ状態」になる。「多難(-20)」な〈肉体抵抗〉テストを行い、失敗したなら「朦朧状態」1つを得る。これは「治療行為」を受けない限り取り除くことができない。'],
  224. [93, '脚粉砕:耐久値-5:「普通(+20)」の〈肉体抵抗〉テストを行い、失敗したなら「伏せ状態」を得て、足の指1本を失う。さら、SLが-1あるごとに追加で1つの足指を失う―「身体欠損(普通)」を被る。「出血状態」2つを得る。'],
  225. [96, '足切断:耐久値-5:「身体欠損(多難)」を被る。「出血状態」3つと「朦朧状態」2つを得て「伏せ状態」になる。'],
  226. [99, 'アキレス腱切断:耐久値-5:苦痛に金切り声を上げながら倒れる。「出血状態」2つと「朦朧状態」2つを得て「伏せ状態」になる。「身体欠損(超多難)」を被る。'],
  227. [100, '骨盤粉砕:即死:'],
  228. ]
  229. ),
  230. }.freeze
  231. # 命中判定
  232. 1 def roll_attack(command)
  233. 47 m = /^WH(\d+)$/.match(command)
  234. 47 else: 10 then: 37 return nil unless m
  235. 10 target_number = m[1].to_i
  236. 10 total = @randomizer.roll_once(100)
  237. 10 then: 10 else: 0 result = result_1d100(total, total, :<=, target_number)&.text
  238. sequence = [
  239. 10 "(#{command})",
  240. total,
  241. result,
  242. additional_result(total, target_number),
  243. ].compact
  244. 10 return sequence.join(" > ")
  245. end
  246. 1 def additional_result(total, target_number)
  247. 10 tens, ones = split_d100(total)
  248. 10 then: 3 if (total > target_number) || (total > 95) # 自動失敗時のファンブル処理も
  249. 3 then: 2 if ones == tens
  250. 2 "ファンブル"
  251. else
  252. else: 1 # 一の位と十の位を入れ替えて参照する
  253. 1 "(#{HIT_PARTS_TABLE.fetch(merge_d100(ones, tens)).content})"
  254. else: 7 end
  255. 7 then: 1 elsif ones == tens
  256. 1 "クリティカル"
  257. else
  258. else: 6 # 一の位と十の位を入れ替えて参照する
  259. 6 HIT_PARTS_TABLE.fetch(merge_d100(ones, tens)).content
  260. end
  261. end
  262. 1 def split_d100(dice)
  263. 10 then: 0 if dice == 100
  264. return 0, 0
  265. else: 10 else
  266. 10 return dice / 10, dice % 10
  267. end
  268. end
  269. 1 def merge_d100(tens, ones)
  270. 7 then: 0 if tens == 0 && ones == 0
  271. 100
  272. else: 7 else
  273. 7 tens * 10 + ones
  274. end
  275. end
  276. 1 HIT_PARTS_TABLE = DiceTable::RangeTable.new(
  277. "命中部位表",
  278. "1D100",
  279. [
  280. # [0, '二足'],
  281. [1..9, '頭部'],
  282. [10..24, '左腕(逆腕)'],
  283. [25..44, '右腕(利腕)'],
  284. [45..79, '胴体'],
  285. [80..89, '左脚'],
  286. [90..100, '右脚'],
  287. ]
  288. )
  289. # 神々の天罰表
  290. 1 def roll_wrath_of_god_table(command)
  291. 37 m = /^WHWGT(\d*)$/.match(command)
  292. 37 else: 5 then: 32 return nil unless m
  293. 5 sin_point = m[1].to_i
  294. 5 total = @randomizer.roll_once(100) + sin_point * 10
  295. 5 then: 1 else: 4 total = 151 if total > 151
  296. sequence = [
  297. 5 "神々の天罰表(#{total})",
  298. WRATH_OF_GOD_TABLE.fetch(total).content
  299. ].compact
  300. 5 return sequence.join(" > ")
  301. end
  302. 1 WRATH_OF_GOD_TABLE = DiceTable::RangeTable.new(
  303. "神々の天罰表",
  304. "1D200",
  305. [
  306. [1..5, '聖なる幻視:神の幻視が君の感覚を苦しめる。「普通」(+20)の〈肉体抵抗〉テストを行なうこと。失敗すると「朦朧状態」1つを得る。幻視の内容はGMが定めること。'],
  307. [6..10, '行ないを顧みよ:次の1週間にわたって、成功したすべての〈祈念〉テストで得られる成功レベル(SL)の上限が+0となる。'],
  308. [11..15, '戒めを心に留めよ:次の1d10+「原罪点」のラウンドにわたって、〈祈念〉技能に-10のペナルティを被る。'],
  309. [16..20, '忠誠を示せ:「伏せ状態」になる。この「状態」は、「普通」(+20)の〈祈念〉テストに成功するまで取り除くことができない。'],
  310. [21..25, '物事には限度というものがある:1d10ラウンドの間、君はいかなる〈祈念〉テストも行なうことができない。'],
  311. [26..30, '我が意図を理解しておらず:次の1d10+「原罪点」の時間数にわたって、君は仕える神に関連するすべての技能(GMが決定する)に-10のペナルティを被る。'],
  312. [31..35, '信念の欠如が心をかき乱すのだ:1d10+「原罪点」のラウンドにわたって、君はいかなる〈祈念〉テストも行なうことができない。'],
  313. [36..40, '我が痛みを分かとう:【頑健力】ボーナスとアーマー・ポイント〔AP〕による修正を無視して、1+「原罪点」の「耐久値」を失う。加えて、「普通」(+20)の〈肉体抵抗〉テストを行なうこと。失敗すると、「朦朧状態」1つを得る。'],
  314. [41..45, '汝の大義に価値はない:君の目標(たち)は「伏せ状態」になる。次の1d10+「原罪点」の日数にわたって、前述の目標に対して行なわれる君の仕える神による「祝福」や「奇跡」は、ことごとく自動失敗となる。'],
  315. [46..50, '戯言はもうやめよ:次の2d10+「原罪点」のラウンドにわたって、君はいかなる〈祈念〉テストも行なうことができない。'],
  316. [51..55, '我が怒りを感じよ:1d10+「原罪点」に等しい「耐久値」を失う。加えて、「手強い」(+0)〈肉体抵抗〉テストを行なうこと。失敗すると、「朦朧状態」1つを得る。'],
  317. [56..60, '汝を助けてはやらぬ:次の1d10+「原罪点」の日数にわたって、君は仕える神に関連するすべての技能(GMが決定する)に-10 のペナルティを被る。'],
  318. [61..65, '神の手傷:1+「原罪点」に等しい数の「出血状態」を得る。'],
  319. [66..70, '目が見えない:「伏せ状態」になることに加えて、1+「原罪点」に等しい数の「目がくらんだ状態」を得る。そのうち後者は、「手強い」(+0)〈祈念〉テストに成功することによってのみ取り除くことができる。このテストに成功することで、1+成功レベル(SL)に等しい数の「目がくらんだ状態」を取り除く。'],
  320. [71..75, '何を犠牲にするのか?:【頑健力】ボーナスとアーマー・ポイント〔AP〕による修正値を無視して、1d10+「原罪点」に等しい「耐久値」を失う。加えて、「難しい」(-10)〈肉体抵抗〉テストを行なうこと。失敗すると、「朦朧状態」1つを得る。'],
  321. [76..80, '我に逆らうとは何事ぞ:君の神は非常に苛立っている。懺悔として、次の1d10+「原罪点」に等しいラウンド数にわたって、君は〈祈念〉テストを自分の「アクション」として行ない続けなければならない。'],
  322. [81..87, '肉体を清めよ:【頑健力】ボーナスとアーマー・ポイント〔AP〕による修正を無視して、2d10+「原罪点」に等しい「耐久値」を失う。加えて、「多難」(-20)な〈肉体抵抗〉テストを行なうこと。失敗すると、「朦朧状態」1つを得る。成功レベル(SL)-4以下で失敗した場合、最短でも1d10ラウンドに渡って継続し、その間は取り除くことができない「気絶状態」となる。'],
  323. [88, '悪魔の干渉:君の守護神に代わり、暗黒の神々が君の懇願に応じる。君のいる場所から2d10ヤード以内に1d10体のレッサー・ディーモンが現れ、最も近い目標(群)を攻撃する。'],
  324. [89..95, '我が怒りに慄け:1+「原罪点」に等しい数の「戦意喪失状態」を得る。'],
  325. [96..100, '懺悔せよ:君は「贖罪」に向かわなければならない。'],
  326. [101..105, '折檻:「耐久値」を0点まで減じ、(君が既にその場にいなくとも)、「気絶状態」になる。この「状態」は、君の「耐久値」が少なくとも1点に回復するまで、取り除くことができない。'],
  327. [106..110, 'みだりに我が名を使うでない:次の1d10+「原罪点」の日数にわたって、君は《祝福》異能と《奇跡》異能を失う。'],
  328. [111..115, 'うぬぼれるな:すべての「所持品」が取り除かれ、君は丸裸になる。君が何らかの魔法アイテムを所持していた場合には、「贖罪」を1つ完遂するごとに、魔法のアイテム1つが君の元へと戻ってくる。'],
  329. [116..120, '我が慈悲を悪用した:次の2d10+「原罪点」の日数にわたって、君は《祝福》異能と《奇跡》異能を失う。'],
  330. [121..125, '汝の邪悪を見よ:君はあらゆるしくじりに関する耐え難い幻視に苦しむ。それは永遠とも思われるが、一瞬に過ぎないものだ。忘れられない経験に対応したあつらえの「心理特徴」(P.190)をGMと相談して作り、君のキャラクターに適用すること。'],
  331. [126..130, '神の雷:君の神が咎める。「耐久値」を0点まで減じ、(君が既にその場にいなくとも)、「炎上状態」1つを得る。'],
  332. [131..135, '我が苦しみをいざ分かたん:「贖罪」を完遂するまでの毎朝、君は1+「原罪点」に等しい数の「出血状態」を得る。'],
  333. [136..140, '破門宣告:2つの「贖罪」を完遂するまで、君は《祝福》異能と《奇跡》異能を失う。最初の贖罪で《祝福》異能が戻り、次の贖罪で《奇跡》異能が戻る。君の神の信徒は全員、君の置かれた状況をひとりでに知る。信徒と交流するすべてのテストは自動的に「超多難」(-30)の難易度となり、プラスの修正値を適用することはできない。'],
  334. [141..145, '汝の価値を示せ:君の神の従者1人が1d100ヤード以内に現れ、怒れる神の性質に従って攻撃や介入、叱責、およびそれらに準ずる行動を取る。'],
  335. [146..150, '追放:君は神に見捨てられた。《祝福》異能と《奇跡》異能を永続的に失い、さらに、〈祈念〉技能でのすべての成長を失う。それに加えて、君の神の信徒は全員、君の置かれた状況をひとりでに知る。信徒と交流するすべてのテストは自動的に「超多難」(-30)の難易度となり、プラスの修正値を適用することはできない。'],
  336. [151..200, '汝の責任を果たせ:最後の審判と向き合うよう、君は神の元へと召喚される。「運命点」が残っていない限り、君は二度と戻ることができない。「運命点」1点を消費することでGMが選択した地点へと戻るが、その上で、146〜150の「追放」の効果を受けねばならない。'],
  337. ]
  338. )
  339. TABLES = {
  340. 1 "WHLT" => HIT_PARTS_TABLE,
  341. "WHFT" => DiceTable::RangeTable.new(
  342. "やっちまった!表",
  343. "1D100",
  344. [
  345. [1..20, '君は自分の体の一部に当ててしまった。「耐久度」1点を失う。'],
  346. [21..40, '君の武器が1ダメージを受ける。次のラウンドの行動順が一番最後になる。'],
  347. [41..60, '君は身体動作の目算を誤る。次のラウンドのアクションに-10。'],
  348. [61..70, '君はひどく躓きバランスを回復するのに手間取る。次の「移動」を失う。'],
  349. [71..80, '君は武器を取り回しを誤る。次の「アクション」を失う。'],
  350. [81..90, '君は筋を違えるか、足首をひねってしまう。「筋断裂(軽度)」の負傷を得る。「致命的負傷」としてカウントされる。'],
  351. [91..100, '君は射程内のランダムな味方を攻撃してしまう。命中判定の出目の1の位をSLとして用いること。攻撃可能な味方が居ない場合は、自己を攻撃してしまい「朦朧状態」1つを得る。'],
  352. ]
  353. ),
  354. "WHMIT" => DiceTable::RangeTable.new(
  355. "小誤発動表",
  356. "1D100",
  357. [
  358. [1..5, '魔女の印:1マイル以内で次に新たに生まれたクリーチャー1体が混沌変異する。'],
  359. [6..10, '酸っぱいミルク:1d100ヤード以内のすべてのミルクが即座に酸っぱくなる。'],
  360. [11..15, '立ち枯れ:君の【意志力】ボーナス×1 マイル以内の農場が立ち枯れの病にかかり、すべての穀物が一夜のうちに腐れてしまう。'],
  361. [16..20, '耳垢閉塞:君の耳が即座に分厚い耳垢で詰まってしまう。「耳鳴り状態」1つを得る。誰かが君に耳掃除してくれない限りこれを取り除くことはできない(〈治療〉技能を用いてテストに成功しなければならない)。'],
  362. [21..25, '魔女の光:君は自分の「魔法体系」に関連した気味の悪い光を放ち、大きな焚き火ほどの明るさで発光する。これは1d10ラウンドにわたって持続する。'],
  363. [26..30, '地獄の囁き:「普通」(+20)の【意志力】テストを行わねばならず、失敗したなら「堕落ポイント」1点を得る。'],
  364. [31..35, '破裂:君の鼻、目、耳からおびただしく出血する。1d10個の「出血状態」を得る。'],
  365. [36..40, '魂が震える:「伏せ状態」になる。'],
  366. [41..45, '結び目ほどき:君の「所持品」のあらゆる留め金が外れ、あらゆる紐の結び目がほどけてしまう。ベルトはずり落ち、ポーチは開き、バッグは落ち、鎧も外れてしまうのだ。'],
  367. [46..50, '気まぐれな装い:君の衣服が自分の意志を持っているかのように振る舞う。「組み付かれた状態」1つを得る。これに抵抗するための【筋力】は1d10×5となる。'],
  368. [51..55, '節制の呪い:1d100ヤード以内のすべての酒が苦くて臭いひどい味になる。'],
  369. [56..60, '魂の消耗:「疲労状態」1 つを得る。これは1d10時間にわたって持続する。'],
  370. [61..65, '困惑する:戦闘に参加しているなら、「不意を討たれた状態」になる。それ以外の場合、君は完全にびくついてしまい、心はあたふたとし、ほんの片時も集中することができなくなる。'],
  371. [66..70, '不浄なる幻視:穢らわしく不浄な行為の幻視が浮かび上がり君を悩ませる。「目がくらんだ状態」1つを得る。「手強い」(+0)〈冷静さ〉テストを行ない、失敗したなら、さらに1つの同「状態」を得る。'],
  372. [71..75, '鼻につく言葉:1d10ラウンドにわたって、すべての〈言語〉テスト(発動テストも含む)に-10のペナルティを被る。'],
  373. [76..80, '恐怖!:「多難」(-20)な〈冷静さ〉テストを行ない、失敗したなら「戦意喪失状態」1つを得る。'],
  374. [81..85, '堕落の呪い:「堕落ポイント」1点を得る。'],
  375. [86..90, '二重の災難:君が発動した呪文の効果は1d10マイル以内の他の場所で発生する。そこでどのような結果が起こるかはGMの裁定による。'],
  376. [91..95, '倍増する不幸:この表を2回ロールする。91〜100が出た場合には再ロールをすること。'],
  377. [96..100, 'ほとばしる混沌:『大誤発動表』でもう一度ロールすること。'],
  378. ]
  379. ),
  380. "WHMAT" => DiceTable::RangeTable.new(
  381. "大誤発動表",
  382. "1D100",
  383. [
  384. [1..5, '亡霊の声:【意志力】×1ヤード以内のすべての者が“混沌の領域”から現れた暗く誘惑的な囁き声を耳にする。知性のあるクリーチャーは皆、「普通」(+20)の〈冷静さ〉テストを行ない、失敗したなら、「堕落ポイント」1点を得る。'],
  385. [6..10, '魔女の目:君の目が1d10時間にわたって、自分の「魔法体系」に関連した不自然な色に変わる。目の色が変わっている間、君はいかなる手段でも取り除くことができない「目がくらんだ状態」1つを得る。'],
  386. [11..15, 'エーテルの衝撃:君は、【頑健力】ボーナスとアーマー・ポイント〔AP〕による修正値を無視して、1d10点の「耐久値」を失う。さらに、「普通」(+20)の〈肉体抵抗〉テストを行ない、失敗したなら、「朦朧状態」1つも得る。'],
  387. [16..20, '死の歩み:君の足跡はその行く手に死を残していく。次の1d10時間にわたって、君の周囲のあらゆる植物は枯れ死に果てる。'],
  388. [21..25, '腸内大暴動:君はお腹の不調を抑えきれず、粗相してしまう。「疲労状態」1つを得るが、これは君が衣服を取り替え、身体を綺麗にするまで取り除くことができない。'],
  389. [26..30, '魂の火:君は自分の「魔法体系」に関連した色の不浄な炎に取り巻かれ、「炎上状態」1つを得る。'],
  390. [31..35, '抑えの効かぬ舌:君は1d10ラウンドにわたって、わけのわからないことを喋りまくる。この間、君は言葉による意思疏通ができず、あらゆる発動テストを行なうこともできないが、それ以外は通常通り行動してもよい。'],
  391. [36..40, '群れの襲撃:君はエーテル体のラット、ジャイアント・スパイダー、スネーク、その他(GM の任意)の群れに囲まれる。関連するクリーチャー種別の通常プロフィールに「群れ」の「クリーチャー特徴」を加えて用いること。1d10ラウンドの終了後に、まだ倒されていなければその群れは撤退する。'],
  392. [41..45, '布人形:君はランダムな方向に1d10ヤード空中に投げ飛ばされ、地面に落ちて1d10点の「耐久値」を失い(アーマー・ポイント〔AP〕は無視する)、さらに「伏せ状態」になる。'],
  393. [46..50, '凍りつく四肢:四肢のひとつ(ランダムに決定する)が1d10ラウンドにわたって動かなくなる。この四肢はまるで「身体欠損」(P.180を参照)になったかのように使い物にならない。'],
  394. [51..55, '闇の目:君は1d10時間にわたって、《第二の視覚》の異能の利益を失う。この時間中、君は〈魔風交信〉テストにも-20のペナルティを被る。'],
  395. [56..60, '混沌の先見:1d10点ぶんの「幸運ポイント」の余剰プールを得る(これは通常の上限を超えても構わない)。君が「幸運ポイント」を1点消費するたびに、「堕落ポイント」を1点獲得する。なお、セッションの終了時に残存している追加で得たポイントはすべて失われる。'],
  396. [61..65, '浮遊:君は“魔力の風”に乗り、1d10分にわたって地上から1d10ヤードの高さに浮かび上がる。他のキャラクターたちが君を無理やり動かすこともできるし、君も呪文や翼などを使って移動することもできるが、そのままにしておくと君が浮かんだ位置に常に戻ってくる。「浮遊」が終了した後に何が起こるかについては、「落下」(P.166)を参照のこと。'],
  397. [66..70, '吐き気:君は吐き気が抑えきれなくなり、君の体内にあった量以上の、悪臭を放つ汚物を吐きちらす。「朦朧状態」1つを得る。これは1d10ラウンドにわたって持続する。'],
  398. [71..75, '混沌の地震:1d100ヤード以内にいるすべてのクリーチャーは「普通」(+20)の〈運動〉テストを行ない、失敗したなら、「伏せ状態」になる。'],
  399. [76..80, '裏切り:暗黒の神々が恐るべき背信を行なうよう君を誘惑する。君が味方の1人に対する攻撃か、その他何らかの裏切り行為に全力を尽くしたなら、「幸運ポイント」をすべて回復できる。君が他のキャラクターに「運命点」1点を失わせたなら、君がその1点の「運命点」を得る。'],
  400. [81..85, '穢らわしい弱体化:1点の「堕落ポイント」に加えて、「疲労状態」1つを獲得し、さらに「伏せ状態」にもなる。'],
  401. [86..90, '凄まじき悪臭:いまや君は鼻が曲がりそうなまでに臭い!君は「攪乱」の「クリーチャー特徴」(P.338)を獲得し、おそらく嗅覚を持つ誰彼すべてからの敵意にさらされる。この効果は1d10時間持続する。'],
  402. [91..95, '力の流出:君は1d10分にわたって、呪文を発動するために使う異能を使用することができない(通常は《秘術魔術》だが、《混沌魔術》や同種の異能ということもありえる)。'],
  403. [96..100, 'エーテルの逆流:君の【意志力】ボーナス×1ヤード以内にいるすべての者は──敵も味方も同様に──(【頑健力】ボーナスとアーマー・ポイント〔AP〕を無視して)1d10点の「耐久値」を失い、さらに「伏せ状態」になる。射程内に目標が存在しなければ、魔法は行き場を失い、君の頭は爆発し、君は即死する。'],
  404. ]
  405. ),
  406. }.freeze
  407. end
  408. end
  409. end

lib/bcdice/game_system/WerewolfTheApocalypse5th.rb

98.82% lines covered

97.5% branches covered

85 relevant lines. 84 lines covered and 1 lines missed.
40 total branches, 39 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class WerewolfTheApocalypse5th < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'WerewolfTheApocalypse5th'
  7. # ゲームシステム名
  8. 1 NAME = 'Werewolf: The Apocalypse 5th Edition'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'わあうふるしあほかりふす5'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・判定コマンド(nWAFx+x または nWAIxRx)
  14. WAFコマンドはRageダイスとダイスプールを個別に指定する。
  15. WAIコマンドはRageダイスをダイスプールの内数として指定する。
  16. 例:難易度2、9ダイスプールでRageダイス3個の場合、それぞれ以下のようなコマンドとなる。
  17. 2WAF6+3
  18. 2WAI9R3
  19. 難易度指定:成功数のカウント、判定成功と失敗、(Rageダイスがある場合)Brutal outcome、Critical処理、Total Failure、Critical Winのチェックを行う
  20. 例) (難易度)WAF(通常ダイス)+(Rageダイス)
  21. (難易度)WAF(通常ダイス)
  22. (難易度)WAI(通常ダイス)R(Rageダイス)
  23. (難易度)WAI(通常ダイス)
  24. 難易度省略:成功数のカウント、判定失敗、(Rageダイスがある場合)Brutal outcome、Critical処理、Total Failureのチェックを行う
  25. 判定成功チェックを行わない
  26. Critical Winのヒントを出力
  27. 例) WAF(通常ダイス)+(Rageダイス)
  28. WAF(通常ダイス)
  29. WAI(通常ダイス)R(Rageダイス)
  30. WAI(通常ダイス)
  31. 難易度0指定:Critical処理と成功数のカウントを行い、全てのチェックを行わない
  32. 例) 0WAF(通常ダイス)+(Rageダイス)
  33. 0WAF(通常ダイス)
  34. 0WAI(通常ダイス)+(Rageダイス)
  35. 0WAI(通常ダイス)
  36. MESSAGETEXT
  37. 1 DIFFICULTY_INDEX = 1
  38. 1 DICE_POOL_RAGE_DICE_NO_INCLUDED_INDEX = 5
  39. 1 RAGE_DICE_NO_INCLUDED_INDEX = 7
  40. 1 COMMAND_RAGE_DICE_INCLUDED_INDEX = 9
  41. 1 DICE_POOL_RAGE_DICE_INCLUDED_INDEX = 10
  42. 1 RAGE_DICE_INCLUDED_INDEX = 12
  43. # 難易度に指定可能な特殊値
  44. 1 NOT_CHECK_SUCCESS = -1 # 判定成功にかかわるチェックを行わない(判定失敗に関わるチェックは行う)
  45. 1 register_prefix('\d*(WAF|(WAI\d*(R\d?)?))')
  46. 1 def eval_game_system_specific_command(command)
  47. 198 m = /\A(\d+)?(((WAF)(\d+)(\+(\d+))?)|((WAI)(\d+)(R(\d+))?))$/.match(command)
  48. 198 else: 198 then: 0 unless m
  49. return ''
  50. end
  51. 198 dice_pool, rage_dice_pool = get_dice_pools(m)
  52. 198 then: 1 else: 197 if dice_pool < 0
  53. 1 return "ダイスプール0のときにRageダイスは指定できません。"
  54. end
  55. 197 then: 2 else: 195 if rage_dice_pool > 5
  56. 2 return "5を超えるRageダイス指定はできません。"
  57. end
  58. 195 dice_text, success_dice, ten_dice, = make_dice_roll(dice_pool)
  59. 195 result_text = "(#{dice_pool}D10"
  60. 195 then: 119 if rage_dice_pool >= 0
  61. 119 rage_dice_text, rage_success_dice, rage_ten_dice, brutal_result_dice = make_dice_roll(rage_dice_pool)
  62. 119 brutal_outcome = brutal_result_dice / 2
  63. 119 ten_dice += rage_ten_dice
  64. 119 success_dice += rage_success_dice
  65. 119 result_text = "#{result_text}+#{rage_dice_pool}D10) > [#{dice_text}]+[#{rage_dice_text}] "
  66. else: 76 else
  67. 76 rage_ten_dice = 0
  68. 76 brutal_outcome = 0
  69. 76 result_text = "#{result_text}) > [#{dice_text}] "
  70. end
  71. 195 success_dice += get_critical_success(ten_dice)
  72. 195 then: 117 else: 78 difficulty = m[DIFFICULTY_INDEX] ? m[DIFFICULTY_INDEX].to_i : NOT_CHECK_SUCCESS
  73. 195 return get_roll_result(result_text, success_dice, ten_dice, rage_ten_dice, brutal_outcome, difficulty)
  74. end
  75. 1 private
  76. 1 def get_dice_pools(m)
  77. 198 rage_dice_included_command = m[COMMAND_RAGE_DICE_INCLUDED_INDEX]
  78. 198 if rage_dice_included_command && rage_dice_included_command == "WAI"
  79. then: 103 # Rage Diceを内数処理するの場合
  80. 103 then: 38 else: 65 rage_dice_pool = m[RAGE_DICE_INCLUDED_INDEX].nil? ? -1 : m[RAGE_DICE_INCLUDED_INDEX].to_i
  81. 103 dice_pool_value = m[DICE_POOL_RAGE_DICE_INCLUDED_INDEX].to_i
  82. 103 then: 38 else: 65 dice_pool = dice_pool_value - (rage_dice_pool < 0 ? 0 : rage_dice_pool)
  83. 103 else: 94 if dice_pool_value > 0 && rage_dice_pool >= dice_pool_value
  84. then: 9 # 1 以上のダイスプール、かつ、Rageダイスがダイスプール以上のとき、ダイスプールが全てRageダイスになる。
  85. 9 dice_pool = 0
  86. 9 rage_dice_pool = dice_pool_value
  87. end
  88. else
  89. else: 95 # Rage DiceがPLによる内数指定の場合
  90. 95 then: 38 else: 57 rage_dice_pool = m[RAGE_DICE_NO_INCLUDED_INDEX].nil? ? -1 : m[RAGE_DICE_NO_INCLUDED_INDEX].to_i
  91. 95 dice_pool = m[DICE_POOL_RAGE_DICE_NO_INCLUDED_INDEX].to_i
  92. end
  93. 198 return dice_pool, rage_dice_pool
  94. end
  95. 1 def get_roll_result(result_text, success_dice, ten_dice, _rage_ten_dice, brutal_outcome, difficulty)
  96. 195 is_critical = ten_dice >= 2
  97. 195 then: 40 if brutal_outcome > 0 && difficulty != 0
  98. 40 success_dice += 4
  99. 40 result_text = "#{result_text} [Brutal outcome] 自動失敗、または 成功数=#{success_dice}"
  100. else: 155 else
  101. 155 result_text = "#{result_text} 成功数=#{success_dice}"
  102. end
  103. 195 then: 89 if difficulty > 0
  104. 89 result_text = "#{result_text} 難易度=#{difficulty}"
  105. 89 then: 51 if success_dice >= difficulty
  106. 51 result_text = "#{result_text} 差分=#{success_dice - difficulty}"
  107. 51 then: 25 else: 26 if is_critical
  108. 25 result_data = Result.critical("#{result_text}:判定成功! [Critical Win]")
  109. 25 then: 8 else: 17 return brutal_outcome > 0 ? result_data.text : result_data
  110. end
  111. 26 result_data = Result.success("#{result_text}:判定成功!")
  112. 26 then: 5 else: 21 return brutal_outcome > 0 ? result_data.text : result_data
  113. else: 38 else
  114. 38 then: 13 if success_dice == 0
  115. 13 return Result.fumble("#{result_text}:判定失敗! [Total Failure]")
  116. else: 25 else
  117. 25 return Result.failure("#{result_text}:判定失敗!")
  118. end
  119. else: 106 end
  120. 106 then: 78 else: 28 elsif difficulty < 0
  121. 78 then: 13 if success_dice == 0
  122. 13 return Result.fumble("#{result_text}:判定失敗! [Total Failure]")
  123. else: 65 else
  124. 65 then: 29 else: 36 if is_critical
  125. 29 result_text = "#{result_text}\n 判定成功なら [Critical Win]"
  126. end
  127. 65 return result_text.to_s
  128. end
  129. end
  130. # 難易度0指定(=全ての判定チェックを行わない)
  131. 28 return result_text.to_s
  132. end
  133. 1 def get_critical_success(ten_dice)
  134. # 10の目が2個毎に追加2成功
  135. 195 return ((ten_dice / 2) * 2)
  136. end
  137. 1 def make_dice_roll(dice_pool)
  138. 314 dice_list = @randomizer.roll_barabara(dice_pool, 10)
  139. 314 dice_text = dice_list.join(',')
  140. 1473 success_dice = dice_list.count { |x| x >= 6 }
  141. 314 ten_dice = dice_list.count(10)
  142. 314 brutal_result_dice = dice_list.count(1) + dice_list.count(2)
  143. 314 return dice_text, success_dice, ten_dice, brutal_result_dice
  144. end
  145. end
  146. end
  147. end

lib/bcdice/game_system/WitchQuest.rb

100.0% lines covered

88.89% branches covered

58 relevant lines. 58 lines covered and 0 lines missed.
9 total branches, 8 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class WitchQuest < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'WitchQuest'
  7. # ゲームシステム名
  8. 1 NAME = 'ウィッチクエスト'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'ういつちくえすと'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~MESSAGETEXT
  13. ・チャレンジ(成功判定)(WQn)
  14.  n回2d6ダイスを振って判定を行います。
  15.  例)WQ3
  16. ・SET(ストラクチャーカードの遭遇表(SETn)
  17.  ストラクチャーカードの番号(n)の遭遇表結果を得ます。
  18.  例)SET1 SET48
  19. MESSAGETEXT
  20. 1 register_prefix('WQ', 'SET')
  21. 1 def eval_game_system_specific_command(command)
  22. 10 else: 1 case command
  23. when: 6 when /WQ(\d+)/
  24. 6 number = Regexp.last_match(1).to_i
  25. 6 return challenge(number)
  26. when: 3 when /SET(\d+)/
  27. 3 number = Regexp.last_match(1).to_i
  28. 3 return getStructureEncounter(number)
  29. end
  30. 1 return nil
  31. end
  32. 1 def challenge(number)
  33. 6 success = 0
  34. 6 results = []
  35. 6 number.times do
  36. 28 value1 = @randomizer.roll_once(6)
  37. 28 value2 = @randomizer.roll_once(6)
  38. 28 then: 26 else: 2 if value1 == value2
  39. 26 success += 1
  40. end
  41. 28 results << "#{value1},#{value2}"
  42. end
  43. 6 successText = "(#{results.join(' / ')}) > " + getSuccessText(success)
  44. 6 return successText
  45. end
  46. 1 def getSuccessText(success)
  47. 6 table = [[0, "失敗"],
  48. [1, "1レベル成功(成功)"],
  49. [2, "2レベル成功(大成功)"],
  50. [3, "3レベル成功(奇跡的大成功)"],
  51. [4, "4レベル成功(歴史的大成功)"],
  52. [5, "5レベル成功(伝説的大成功)"],
  53. [6, "6レベル成功(神話的大成功)"],]
  54. 6 then: 3 else: 3 if success >= table.last.first
  55. 3 return table.last.last
  56. end
  57. 3 return get_table_by_number(success, table)
  58. end
  59. 1 def getStructureEncounter(number)
  60. 3 debug("getStructureEncounter number", number)
  61. 3 tables = [[1, ['船から降りてきた', '魚を売っている', '仕事で忙しそうな', '異国から来た', 'おもしろおかしい', '汗水流している']],
  62. [2, ['おかしな格好をした', '歌を歌っている', 'ステキな笑顔をした', '日なたぼっこをしている', '悩んでいる', '旅をしている']],
  63. [3, ['待ちぼうけをしている', '壁に登っている', 'タバコを吸っている', '踊りを踊っている', '幸せそうな', '向こうから走ってくる']],
  64. [4, ['見張りをしている', 'しゃべれない', '見張りをしている', '一輪車に乗った', '元気いっぱいの', '真面目な']],
  65. [5, ['ウソつきな', '買い物をしている', 'ギターを弾いている', 'あなたのほうをじっと見ている', 'ポップコーンを売っている', '屋台を出している']],
  66. [6, ['子供を探している', '時計を直している', '物乞いをしている', '気象実験をしている', '飛び降りようとしている', '時間をきにしている']],
  67. [7, ['目の見えない', '金持ちそうな', '一人歩きをしたことがない', 'ふられてしまった', '待ち合わせをしている', '道に迷った']],
  68. [8, ['お祈りをしている', 'スケッチをしている', '勉強熱心な', '記念碑を壊そうとしている', '大きな声で文句をいっている', '記念撮影している']],
  69. [9, ['隠れている', 'はしごに登っている', '鐘を鳴らしている', '共通語の通じない', '記憶を失った', 'あなたのほうにバタッと倒れた']],
  70. [10, ['暇そうな', '笑ったことがない', 'ぶくぶくと太った', '後継者を探している', '王様におつかえしている', '愛国心旺盛な']],
  71. [11, ['閉じ込められた', '悲しそうな', '怒っている', '降りれなくなっている', 'もの憂げな', '飛ぼうとしている']],
  72. [12, ['釣りをしている', '泳いでいる', '川に物を落としてしまった', '砂金を掘っている', '川にゴミを捨てている', 'カエルに化かされてしまった']],
  73. [13, ['世間話をしている', '結婚を薦めたがる', 'いやらしい話の好きな', '選択をしている', '水を汲んでいる', '井戸に落ちてしまった']],
  74. [14, ['人におごりたがる', '踊り子をしている', '賭けをしている', '泣き上戸な', '飲み比べをしている', '自慢話をしている']],
  75. [15, ['素朴そうな', '田舎者の', 'あなたをだまそうとしている', 'ケンカをしている', '泊まるお金のない', 'あなたに依頼をしにきた']],
  76. [16, ['悪い占いの結果しか言わない', 'あなたに嫉妬している', '魅惑的な', 'おしつけがましい', 'いいかげんな占いしかしない', '変わった占いをしている']],
  77. [17, ['かくれんぼをしている', 'あまやどりをしている', '(ここにはだれもいません)', '家の掃除をしている', '取り壊しをしようとしている', '昔ここに住んでいた']],
  78. [18, ['畑を耕している', '畑を荒らしている', '畑泥棒の', '収穫している', '日焼けして真っ黒な', '嫁いできた(婿にきた)']],
  79. [19, ['粉をひいている', '馬に乗って風車に突進している', '風が吹かなくて困っている', '寝ている', '筋骨りゅうりゅうな', '遊んでいる']],
  80. [20, ['パーティーをしている', '酔っ払っている', '酒を仕込んでいる', '即売会をしている', '笑っている', '太った']],
  81. [21, ['ひとりたたずむ', '花から生まれた', '花が大好きな', '花粉症の', '花を買いにきた', 'ラグビーをやって花をあらしてる']],
  82. [22, ['几帳面な', '眼鏡をかけた', 'なまいきな', 'なわとびをしている', '困っている', 'ませている']],
  83. [23, ['本を読んでいる', '世間話をしたがる', '派手な格好をした', '勉強熱心な', 'うるさい', '魔女のことについて調べている']],
  84. [24, ['神父さんに相談をしている', '結婚式を挙げている', '物静かな', '片足の無い', '熱い視線を送ってくる', '挑発してくる']],
  85. [25, ['頑固な', '刀の切れ味をためしたがる', 'いいかげんな性格の', 'スグに弟子にしたがる', '見せの前でウロウロしている', '道を尋ねている']],
  86. [26, ['不機嫌な', '客の意見を聞かない', '物を売らない', '不幸な気前のいい', '発明家の']],
  87. [27, ['恋人にプレゼントを探している', '香り中毒になった', '客に手伝わせる', 'おまじないの好きな', '人好きのする', 'いじめっこな']],
  88. [28, ['騒がしい', 'お菓子を食べて涙を流している', '笑いの止まらない', '甘い物に目がない', '別れ話をしている', 'あなたをお茶に誘う']],
  89. [29, ['フランスパンを盗んで走る', 'しらけた顔をした', '店番をする', 'あなたをバイトで使いたがる', '変なパンしか作らない', '朝が苦手な']],
  90. [30, ['偏屈な', '威勢のいい', 'ケンカっぱやい', '野次馬根性の強い', '肉が食べれない', '心優しく気前がいい']],
  91. [31, ['夫婦ケンカをしている', '猫に魚を盗られた', '助けを求めている', '魚の種類がわからない', '『おいしい』としかいわない', 'あやしい']],
  92. [32, ['ヤンキー風の', '自分がかっこいいと思っている', '力自慢の', '元は王様だといいはる', '魔女のファンだという', '子沢山の']],
  93. [33, ['わがままな', 'かっこいい', '独り言を言っている', '変わった料理しかださない', '目茶苦茶辛い料理を食べている', 'デートをしている']],
  94. [34, ['仮病を使っている', '不治の病を持った', '”おめでた”の', 'フケた顔した', '髪の毛を染めた', '(健康でも)病名をいいたがる']],
  95. [35, ['実験をしたがる', '精力をつけたがっている', '惚れ薬を探している', '薬づけになっている', 'この町まで薬を売りに来た', '睡眠薬で自殺をしようとしている']],
  96. [36, ['服まで質に入れた', '値段にケチをつけている', '疲れている', '子供を質に入れようとしている', '涙もろい', '人間不信な']],
  97. [37, ['着飾った', 'おねだりしている', '退屈そうな', '見栄っぱりな', '高いものを薦める', '宝石など買うつもりのない']],
  98. [38, ['だだをこねている', 'ぬいぐるみを抱いている', 'あなたを侵略者と考えている', 'あなたの”おしり”にさわる', '幸せのおもちゃを売っている', 'あなたを自分の子と間違えている']],
  99. [39, ['人の話を聞かない', '気分屋な', 'カリアゲしかできない', 'うわさ話の好きな', '自動販売機を開発したという', 'おせっかいな']],
  100. [40, ['お風呂あがりの', 'こきつかわれている', 'シェイプアップしている', '人から追われている', '人の体をじろじろと見る', 'この町を案内してほしいという']],
  101. [41, ['サングラスをかけた', 'みんな自分のファンと思っている', 'あなたを役者と勘違いしている', 'あなたはスターになれるという', '手品をしている', '『いそがしい』をいい続けている']],
  102. [42, ['ギャンブルをしている', '競技に出場している', '全財産を賭けている', '勇敢な', '参加者を募っている', '情けない競技(闘技)をしてる']],
  103. [43, ['ダンスを踊っている', 'ブレイクダンスをして場違いな', '子供を背中におんぶしている', 'あなたと踊りたがる', '踊ったことのない', '食べることに夢中な']],
  104. [44, ['2階からお金をばらまいている', '窓の奥で涙をながしている', '窓から忍びこもう', 'ピアノを弾いている', 'ここに住んでいる', '家に招待したがる']],
  105. [45, ['馬にブラシをかけている', '気性の激しい', '騎手を探している', '馬と話ができる', '馬の生まれ変わりという', '馬を安楽死させようか迷っている']],
  106. [46, ['いたずら好きな', 'ライバル意識の強い', '魔法の下手な', '魔法を信じない', '自分を神と思っている', '魔法を使って人を化かしたがる']],
  107. [47, ['傷だらけな', '両手に宝物を持った', 'かわいい', '地図を見ながら出てきている', '剣を持った', 'ダンジョンの主といわれる']],
  108. [48, ['墓参りをしている', '耳の遠い', '死んでしまった', '葬式をしている', 'きもだめしをしている', '墓守をしている']],]
  109. 3 table = get_table_by_number(number, tables, nil)
  110. 3 then: 0 else: 3 return nil if table.nil?
  111. 3 text, index = get_table_by_1d6(table)
  112. 3 person = getPersonTable1()
  113. 3 return "SET#{number} > #{index}:#{text}#{person}"
  114. end
  115. 1 def getPersonTable1()
  116. 5 gotoNextTable = lambda { "表2へ" + getPersonTable2() }
  117. 3 table = [[11, "おじさん"],
  118. [12, "おばさん"],
  119. [13, "おじいさん"],
  120. [14, "おばあさん"],
  121. [15, "男の子"],
  122. [16, "女の子"],
  123. [22, "美少女"],
  124. [23, "美少年"],
  125. [24, "青年"],
  126. [25, "少年"],
  127. [26, "男女(カップル)"],
  128. [33, "新婚さん"],
  129. [34, "お兄さん"],
  130. [35, "お姉さん"],
  131. [36, "店主(お店の人)"],
  132. [44, "王様"],
  133. [45, "衛兵"],
  134. [46, "魔女"],
  135. [55, "お姫様"],
  136. [56, gotoNextTable],
  137. [66, gotoNextTable],]
  138. 3 getPersonTable(table)
  139. end
  140. 1 def getPersonTable2()
  141. 4 gotoNextTable = lambda { "表3へ" + getPersonTable3() }
  142. 2 table = [[11, "魔法使い"],
  143. [12, "観光客"],
  144. [13, "先生"],
  145. [14, "探偵"],
  146. [15, "刷"],
  147. [16, "お嬢様"],
  148. [22, "お嬢様"],
  149. [23, "紳士"],
  150. [24, "ご婦人"],
  151. [25, "女王様"],
  152. [26, "職人さん"],
  153. [33, "女子高生"],
  154. [34, "学生"],
  155. [35, "剣闘士"],
  156. [36, "鳥"],
  157. [44, "猫"],
  158. [45, "犬"],
  159. [46, "カエル"],
  160. [55, "蛇"],
  161. [56, gotoNextTable],
  162. [66, gotoNextTable],]
  163. 2 getPersonTable(table)
  164. end
  165. 1 def getPersonTable3()
  166. 4 gotoNextTable = lambda { "表4へ" + getPersonTable4() }
  167. 2 table = [[11, "貴族"],
  168. [12, "いるか"],
  169. [13, "だいこん"],
  170. [14, "じゃがいも"],
  171. [15, "にんじん"],
  172. [16, "ドラゴン"],
  173. [22, "ゾンビ"],
  174. [23, "幽霊"],
  175. [24, "うさぎ"],
  176. [25, "天使"],
  177. [26, "悪魔"],
  178. [33, "赤ちゃん"],
  179. [34, "馬"],
  180. [35, "石"],
  181. [36, "お母さん"],
  182. [44, "妖精"],
  183. [45, "守護霊"],
  184. [46, "猫神様"],
  185. [55, "ロボット"],
  186. [56, "恐ろしい人"],
  187. [66, gotoNextTable],]
  188. 2 getPersonTable(table)
  189. end
  190. 1 def getPersonTable4()
  191. 2 table = [[11, "魔女エディス"],
  192. [12, "魔女レーデルラン"],
  193. [13, "魔女キリル"],
  194. [14, "大魔女”ロロ”様"],
  195. [15, "エディスのお母さん”エリー”"],
  196. [16, "猫トンガリ"],
  197. [22, "猫ヒューベ"],
  198. [23, "猫ゆうのす"],
  199. [24, "猫集会の集団の一団"],
  200. [25, "岩"],
  201. [26, "PCの母"],
  202. [33, "PCの父"],
  203. [34, "PCの兄"],
  204. [35, "PCの姉"],
  205. [36, "PCの弟"],
  206. [44, "PCの妹"],
  207. [45, "PCの遠い親戚"],
  208. [46, "PCの死んだはずの両親"],
  209. [55, "初恋の人"],
  210. [56, "分かれた女(男)、不倫中の相手、または独身PCの場合、二股をかけている二人の両方"],
  211. [66, "宇宙人"],]
  212. 2 getPersonTable(table)
  213. end
  214. 1 def getPersonTable(table)
  215. 9 number = @randomizer.roll_d66(D66SortType::ASC)
  216. 9 debug("getPersonTable number", number)
  217. 9 " > #{number}:" + get_table_by_number(number, table)
  218. end
  219. end
  220. end
  221. end

lib/bcdice/game_system/WoW.rb

100.0% lines covered

94.44% branches covered

60 relevant lines. 60 lines covered and 0 lines missed.
18 total branches, 17 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class WoW < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'WoW'
  7. # ゲームシステム名
  8. 1 NAME = 'ワンダーオブワンダラー'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'わんたあおふわんたらあ'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. 行為判定 nWW12@s#f<=x
  14. n: ダイス数
  15. @s = 大成功値(省略可:デフォルトは1)
  16. #f = 大失敗値(省略可:デフォルトは12)
  17. x = 目標値(省略可:デフォルトは6)
  18. 例)1WW12 5WW12<=6 6WW12@5#3<=7+1
  19. ランダムギフトガチャ表 GG
  20. ランダムギフトガチャ表(アルファベット指定) GGx 例)GGA GGB
  21. ファンブル表 FT
  22. INFO_MESSAGE_TEXT
  23. 1 register_prefix('\d*WW12', 'GG', 'GGA', 'GGB', 'GGC', 'GGD', 'GGE', 'GGF', 'GGG', 'GGH', 'FT')
  24. TABLES = {
  25. 1 'A' => [
  26. '演者の声', '言いくるめ', '誤魔化し', '代弁者', '腕利き弁護人', '魔性', '魔術', '魔法的物理', '誤り指摘', '専門知識', '理力増幅', '協力的な有識者'
  27. ],
  28. 'B' => [
  29. '百科全書', '地道な下調べ', '思い…出した!', '目星', 'ハッキング', '再考察', '迷探偵', '逆転の発想', '炯眼', '安楽椅子探偵', '密室トリック解明', '丁寧な処置'
  30. ],
  31. 'C' => [
  32. '慈愛', 'クイックヒール', 'エリアヒール', 'クリアランス', '俯瞰視点', 'パターン化', '瞬時看破', '警鐘', '賢者の瞳', '千里眼', '危険感知', 'リバーサル'
  33. ],
  34. 'D' => [
  35. '転禍為福', '受け身', '九死に一生', '軽業', 'バックドア', '着服', '闇に隠れる', '変装', '証拠隠滅', 'サポート', '技師の指', '妨害'
  36. ],
  37. 'E' => [
  38. 'ゴッドハンド', '生存者の切り札', '狙撃', 'プラチナ免許', 'ドライバーズ・ハイ', '相乗り', '愛車/愛馬', 'ビーストフレンズ', 'ドゥ・ライブ', 'カツアゲ', 'マッドドッグ', '目の上の瘤'
  39. ],
  40. 'F' => [
  41. '叱咤激励', 'ふいに見せた優しさ', 'スゴ味', '達人', '必殺技', '二刀流', '急所狙い', 'ジャンプショット', 'パルクール', '疾風怒濤', 'スパート', '走為上'
  42. ],
  43. 'G' => [
  44. 'ヒット&アウェイ', 'ウーバー', '割れもの注意', 'もしもの備え', 'アブダクション', '追加機材', '自在配送', '不屈の精神', '防壁', '心頭滅却', '三時間しか寝てない', 'βエンドルフィン'
  45. ],
  46. 'H' => [
  47. '怒髪天', '頭の体操', '精神統一', 'リトルラック', 'いいね!', '幻視', '慎重性', 'バレットストッパー', '褪せぬ想い', 'アピール上手', '土俵際の魔術師', '真実の愛'
  48. ],
  49. 'FT' => [
  50. '何も起きなかった! ラッキー(?)',
  51. 'ランダムに武器または防具が外れる。該当箇所に何も装備していなければ1点のダメージ(軽減無効)を受ける。',
  52. 'GMの指定したLOVEの【深度】が1増加する。誰かに対するLOVEを新規取得させても良い。',
  53. 'GMの指定したハンドアウト1つの強度が[自身のソウルLV/2]増加する。',
  54. '1点のダメージ(軽減無効)を受ける。',
  55. 'プレイス内のPCが所持している消耗品からGMが1つ指定し、破壊する。破壊したくない場合、かわりに自身のHPを最大値の1/3(切り捨て)減らす。',
  56. '不調強度[自身のソウルLV/2]のランダムな不調を受ける。',
  57. 'ファンブル表を2回振る。この効果は判定につき1度までで、以降は1点のダメージ(軽減無効)を受ける。',
  58. 'ランダムなLOVEの【深度】が1減少する。',
  59. 'ランダムなLOVEの【エモ】が2増加する。',
  60. 'トラブルが発生する。ランダムトラブル表を使用し、場にトラブルのハンドアウトを追加する。',
  61. 'ランダムなギフト1つのMPが0になる。'
  62. ]
  63. }.freeze
  64. 1 def eval_game_system_specific_command(command)
  65. 19 case command
  66. when: 2 when 'GG'
  67. 2 return roll_gg
  68. when: 1 when /^GG([A-H])$/
  69. 1 return roll_table(::Regexp.last_match(1))
  70. when: 1 when 'FT'
  71. 1 return roll_fumble_table
  72. else: 15 else
  73. 15 return roll_wow(command)
  74. end
  75. end
  76. 1 private
  77. 1 def roll_gg
  78. 2 dice_results = @randomizer.roll_barabara(2, 12)
  79. 2 first_roll = dice_results[0]
  80. 2 second_roll = dice_results[1]
  81. 2 then: 1 else: 1 if first_roll >= 9
  82. 1 return "GG > 自由(アルファベットを決めてGGXを振る)"
  83. end
  84. 1 alphabet = (64 + first_roll).chr
  85. 1 table = TABLES[alphabet]
  86. 1 return "ランダムギフトガチャ #{alphabet}-#{second_roll} > #{table[second_roll - 1]}"
  87. end
  88. 1 def roll_table(alphabet)
  89. 1 table = TABLES[alphabet]
  90. 1 dice_result = @randomizer.roll_once(12)
  91. 1 return "ランダムギフトガチャ #{alphabet}-#{dice_result} > #{table[dice_result - 1]}"
  92. end
  93. 1 def roll_fumble_table
  94. 1 dice_result = @randomizer.roll_once(12)
  95. 1 table = TABLES['FT']
  96. 1 return "FT(#{dice_result}) > #{table[dice_result - 1]}"
  97. end
  98. 1 def roll_wow(command)
  99. # コマンドの解析
  100. 15 m = /^(\d+)WW12(?:@(\d+))?(?:#(\d+))?(?:<=(\d+))?$/.match(command)
  101. 15 else: 15 then: 0 return nil unless m
  102. 15 num_dice = m[1].to_i # 振るダイスの数
  103. 15 then: 8 else: 7 critical_success_value = m[2] ? m[2].to_i : 1 # 大成功の値(デフォルトは1)
  104. 15 then: 8 else: 7 critical_fail_value = m[3] ? m[3].to_i : 12 # 大失敗の値(デフォルトは12)
  105. 15 then: 14 else: 1 success_threshold = m[4] ? m[4].to_i : 6 # 成功の閾値(デフォルトは6)
  106. 15 then: 1 if m[4].nil?
  107. 1 command_with_defaults = "#{m[1]}WW12<=#{success_threshold}"
  108. else: 14 else
  109. 14 command_with_defaults = command
  110. end
  111. # ダイスを振る
  112. 15 dice_results = @randomizer.roll_barabara(num_dice, 12)
  113. # 出目を分類
  114. 71 critical_success = dice_results.count { |r| r <= critical_success_value } # 大成功の数
  115. 71 critical_fail = dice_results.count { |r| r >= critical_fail_value } # 大失敗の数
  116. 71 normal_success = dice_results.count { |r| (r > critical_success_value) && (r <= success_threshold) && r < critical_fail_value }
  117. 15 critical_success_first = critical_success
  118. 15 critical_fail_first = critical_fail
  119. # 大成功と大失敗の相殺
  120. 15 offset = [critical_success, critical_fail].min
  121. 15 critical_success -= offset
  122. 15 critical_fail -= offset
  123. # 成功数とファンブルの判定
  124. 15 successes = normal_success + (critical_success * 2)
  125. 15 is_fumble = critical_fail > 0
  126. # 結果をBCDICE::Resultで構造化
  127. 15 BCDice::Result.new.tap do |r|
  128. 15 then: 2 else: 13 r.text = "(#{command_with_defaults}) > [#{dice_results.join(',')}] > 成功数#{successes}(大成功#{critical_success_first}個、大失敗#{critical_fail_first}個)#{is_fumble ? ' > ファンブル!' : ''}"
  129. 15 r.critical = critical_success > 0
  130. 15 r.fumble = is_fumble
  131. 15 r.success = successes > 0 && !is_fumble # 成功数が0より大きく、ファンブルがない場合に成功
  132. 15 r.failure = successes == 0 || is_fumble # 成功数が0、またはファンブルがある場合に失敗
  133. end
  134. end
  135. end
  136. end
  137. end

lib/bcdice/game_system/WorldOfDarkness.rb

100.0% lines covered

100.0% branches covered

68 relevant lines. 68 lines covered and 0 lines missed.
29 total branches, 29 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class WorldOfDarkness < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'WorldOfDarkness'
  7. # ゲームシステム名
  8. 1 NAME = 'ワールド・オブ・ダークネス'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'わあるとおふたあくねす'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・判定コマンド(xSTn+y or xSTSn+y or xSTAn+y)
  14.  (ダイス個数)ST(難易度)+(自動成功)
  15.  (ダイス個数)STS(難易度)+(自動成功) ※出目10で振り足し、振り足し分の出目1で打ち消されない
  16.  (ダイス個数)STB(難易度)+(自動成功) ※出目10で振り足し、振り足し分の出目1で打ち消される
  17.  (ダイス個数)STA(難易度)+(自動成功) ※出目10は2成功 [20thルール]
  18.  難易度=省略時6
  19.  自動成功=省略時0、出目1で打ち消されない自動成功を指定
  20. INFO_MESSAGE_TEXT
  21. 1 register_prefix('\d+ST')
  22. 1 def eval_game_system_specific_command(command)
  23. 74 difficulty = 6
  24. 74 auto_success = 0
  25. 74 enabled_reroll = false
  26. 74 enabled_reroll_with_botch = false
  27. 74 enabled_20th = false
  28. 74 md = command.match(/\A(\d+)(ST[SAB]?)(\d+)?([+-]\d+)?/)
  29. 74 dice_pool = md[1].to_i
  30. 74 else: 22 case md[2]
  31. when: 24 when 'STS'
  32. 24 enabled_reroll = true
  33. when: 22 when 'STA'
  34. 22 enabled_20th = true
  35. when: 6 when 'STB'
  36. 6 enabled_reroll_with_botch = true
  37. end
  38. 74 then: 27 else: 47 difficulty = md[3].to_i if md[3]
  39. 74 then: 25 else: 49 auto_success = md[4].to_i if md[4]
  40. 74 then: 3 else: 71 difficulty = 6 if difficulty < 2
  41. 74 sequence = []
  42. 74 sequence.push "DicePool=#{dice_pool}, Difficulty=#{difficulty}, AutomaticSuccess=#{auto_success}"
  43. # 出力では Difficulty=11..12 もあり得る
  44. 74 then: 3 else: 71 difficulty = 10 if difficulty > 10
  45. 74 total_success = 0
  46. 74 total_botch = 0
  47. 74 once_success = false
  48. 74 dice, ten_success, success, botch = roll_wod(dice_pool, difficulty)
  49. 74 sequence.push dice.join(',')
  50. 74 total_success += success
  51. 74 total_botch += botch
  52. # 成功がひとつでもあったか覚えておく
  53. 74 then: 54 else: 20 once_success = true if success > 0 || ten_success > 0
  54. 74 if enabled_20th
  55. then: 22 # 20周年記念版なら10の目は2成功扱い
  56. 22 total_success += ten_success * 2
  57. else
  58. else: 52 # Revised Editionでは10は1成功と数える
  59. 52 total_success += ten_success
  60. # 振り足し判定ありなら10が出ただけ振り足しを行う
  61. 52 then: 30 else: 22 if enabled_reroll || enabled_reroll_with_botch
  62. 30 body: 17 while ten_success > 0
  63. 17 dice, ten_success, success, botch = roll_wod(ten_success, difficulty)
  64. 17 sequence.push dice.join(',')
  65. 17 total_success += (success + ten_success)
  66. 17 else: 13 if enabled_reroll_with_botch
  67. then: 4 # 振り足しでのボッチありなら出目1をカウントする
  68. 4 total_botch += botch
  69. end
  70. end
  71. end
  72. end
  73. 74 total_success -= [total_success, total_botch].min
  74. 74 total_success += auto_success # 意志力による自動成功は打ち消されない
  75. 74 then: 53 if total_success > 0
  76. 53 sequence.push "成功数#{total_success}"
  77. 53 else: 21 return Result.success(sequence.join(' > '))
  78. 21 elsif total_botch > 0 && once_success == false
  79. then: 5 # ボッチが存在し、かつ成功がひとつもない場合のみ大失敗
  80. 5 sequence.push "大失敗"
  81. 5 return Result.fumble(sequence.join(' > '))
  82. else: 16 else
  83. 16 sequence.push "失敗"
  84. 16 return Result.failure(sequence.join(' > '))
  85. end
  86. end
  87. # 出目10と1、難易度以上が出た成功の目をカウントする。
  88. # それぞれの解釈はバージョンによって異なるため、呼び出し元で行う。
  89. 1 def roll_wod(dice_pool, difficulty)
  90. # FIXME: まとめて振る
  91. 91 dice = Array.new(dice_pool) do
  92. 279 dice_now = @randomizer.roll_once(10)
  93. 279 dice_now
  94. end
  95. 91 dice.sort!
  96. 91 success = 0
  97. 91 botch = 0
  98. 91 ten_success = 0
  99. 91 dice.each do |d|
  100. 279 else: 98 case d
  101. when: 39 when 10
  102. 39 ten_success += 1
  103. when: 63 when difficulty...10
  104. 63 success += 1
  105. when: 79 when 1
  106. 79 botch += 1
  107. end
  108. end
  109. 91 return dice, ten_success, success, botch
  110. end
  111. end
  112. end
  113. end

lib/bcdice/game_system/WorldsEndFrontline.rb

100.0% lines covered

100.0% branches covered

8 relevant lines. 8 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/Bloodorium"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class WorldsEndFrontline < Bloodorium
  6. # ゲームシステムの識別子
  7. 1 ID = 'WorldsEndFrontline'
  8. # ゲームシステム名
  9. 1 NAME = 'ワールドエンドフロントライン'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'わあるとえんとふろんとらいん'
  12. 1 register_prefix_from_super_class()
  13. end
  14. end
  15. end

lib/bcdice/game_system/YankeeMustDie.rb

80.88% lines covered

61.76% branches covered

68 relevant lines. 55 lines covered and 13 lines missed.
34 total branches, 21 branches covered and 13 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class YankeeMustDie < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "YankeeMustDie"
  7. # ゲームシステム名
  8. 1 NAME = "ヤンキーマストダイ"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "やんきいますとたい"
  11. 1 HELP_MESSAGE = <<~TEXT
  12. ■ 判定の方法
  13. 基本形式:
  14. (YD+a>=b) または (YD+a>b)
  15. a:能力値、技能レベル、ドウグ等による修正値(複数指定可)
  16. b:目標となる成功段階
  17. ■ 成功の条件
  18. >=b:目標となる成功段階b以上の場合に成功となります。この条件では、目標となる成功段階と同じ数値でも成功とみなされます。
  19. >b:目標となる成功段階bより高い成功段階を出した場合に成功となります。この条件では、目標となる成功段階と同じ数値では失敗となります。
  20. ■ 各種表
  21.  関係表 RT
  22.  場面表 ST
  23.  ハプニング表 HT
  24.  闇堕ち表 DT
  25. TEXT
  26. 1 def initialize(command)
  27. 17 super(command)
  28. 17 @sort_barabara_dice = true
  29. 17 @sides_implicit_d = 10
  30. end
  31. 1 def eval_game_system_specific_command(command)
  32. 17 return check_action(command) || roll_tables(command, TABLES)
  33. end
  34. 1 def check_action(command)
  35. 17 parser = Command::Parser.new("YD", round_type: @round_type)
  36. .restrict_cmp_op_to(:>=, :>, nil)
  37. 17 parsed = parser.parse(command)
  38. 17 else: 13 then: 4 unless parsed
  39. 4 return nil
  40. end
  41. 13 dice_all = []
  42. 13 loop do
  43. 17 dice_list = @randomizer.roll_barabara(3, 10).sort
  44. 17 dice_all.push(dice_list)
  45. 17 else: 4 then: 13 break unless dice_list.uniq.one?
  46. end
  47. 13 achievement_value = dice_all.flatten.sum(parsed.modify_number)
  48. 13 then: 1 if achievement_value <= 9
  49. 1 else: 12 success_level = 0
  50. 12 then: 2 elsif achievement_value <= 19
  51. 2 else: 10 success_level = 1
  52. 10 then: 7 elsif achievement_value <= 29
  53. 7 else: 3 success_level = 2
  54. 3 then: 3 elsif achievement_value <= 39
  55. 3 else: 0 success_level = 3
  56. then: 0 elsif achievement_value <= 49
  57. else: 0 success_level = 4
  58. then: 0 elsif achievement_value <= 59
  59. else: 0 success_level = 5
  60. then: 0 elsif achievement_value <= 69
  61. else: 0 success_level = 6
  62. then: 0 elsif achievement_value <= 79
  63. else: 0 success_level = 7
  64. then: 0 elsif achievement_value <= 89
  65. else: 0 success_level = 8
  66. then: 0 elsif achievement_value <= 99
  67. success_level = 9
  68. else: 0 else
  69. success_level = 10
  70. end
  71. 13 then: 4 if parsed.cmp_op == :>
  72. 4 is_success = success_level > parsed.target_number
  73. 4 is_failure = !is_success
  74. 4 else: 9 then: 2 else: 2 success_message = is_success ? '成功' : '失敗'
  75. 9 then: 7 elsif parsed.cmp_op == :>=
  76. 7 is_success = success_level >= parsed.target_number
  77. 7 is_failure = !is_success
  78. 7 then: 4 else: 3 success_message = is_success ? '成功' : '失敗'
  79. else: 2 else
  80. 2 is_success = false
  81. 2 is_failure = false
  82. 2 success_message = nil
  83. end
  84. 13 dice_to_message_arr = []
  85. 13 dice_all.each do |arr|
  86. 17 dice_to_message_arr.append("#{arr.sum}[#{arr.join(',')}]")
  87. end
  88. sequence = [
  89. 13 parsed.to_s,
  90. format("#{dice_to_message_arr.join(' + ')} %+d", parsed.modify_number),
  91. achievement_value,
  92. "成功段階#{success_level}"
  93. ]
  94. 13 then: 11 else: 2 if success_message
  95. 11 sequence.append(success_message)
  96. end
  97. 13 Result.new.tap do |r|
  98. 13 r.text = sequence.join(" > ")
  99. 13 r.success = is_success
  100. 13 r.failure = is_failure
  101. end
  102. end
  103. TABLES = {
  104. 1 'RT' => DiceTable::Table.new(
  105. '関係表',
  106. '1D10',
  107. [
  108. 'マブダチ:相手とは、マブダチ(親友) だ。いつからマブダチなのかはプレイヤー同士で相談して決めること。',
  109. '先輩/後輩:相手とは、先輩と後輩の間柄だ。なんの先輩後輩かはプレイヤー同士で相談して決めること。',
  110. '兄弟:相手とは、血縁であったり契りを交わした兄弟だ。兄弟になった経緯はプレイヤー同士で相談して決めること。',
  111. 'ライバル:相手とは、良きライバル関係にある。どのようなライバル関係かはプレイヤー同士で相談して決めること。',
  112. '仲間:相手とは、同じチームなどに所属している仲間だ。どんなチームかはプレイヤー同士で相談して決めること。',
  113. 'ジモティー:相手とは、同じ地元の仲間、幼馴染だ。いつから幼馴染なのかはプレイヤー同士で相談して決めること。',
  114. 'おな中:相手とは、出身中学(小学校・高校も可) が同じだ。どんな中学だったのかはプレイヤー同士で決めること。',
  115. '相棒:相手は、唯一無二の相棒だ。いつから相棒なのかはプレイヤー同士で相談して決めること。',
  116. 'ゾッコン:相手は、唯一無二の相棒だ。いつから相棒なのかはプレイヤー同士で相談して決めること。',
  117. '犬猿:相手とは、犬猿の仲である。犬猿の仲であるが、なぜ共に行動するのかはプレイヤー同士で相談して決めること。'
  118. ]
  119. ),
  120. 'ST' => DiceTable::Table.new(
  121. '場面表',
  122. '1D10',
  123. [
  124. 'サ店(喫茶店)',
  125. 'クラブ',
  126. '工業団地',
  127. '神社/教会',
  128. '学校',
  129. '埠頭',
  130. '繁華街',
  131. 'ゲーセン',
  132. '公園',
  133. '河原'
  134. # 特殊な場合のみ発生する
  135. # '病院'
  136. ]
  137. ),
  138. 'HT' => DiceTable::Table.new(
  139. 'ハプニング表',
  140. '1D10',
  141. [
  142. '単車ドロ:愛車を盗まれる。次の自身の手番を迎えるまで、愛車が1台使用不能になる。所有している愛車が複数ある場合はランダムに1台を選ぶ。',
  143. '職質:サツにドウグを取り上げられる。次の自身の手番を迎えるまで、素手を除くドウグが1つ使用不能になる。所有しているドウグが複数ある場合はランダムに1つを選ぶ。',
  144. '不調:どうにも愛車やドウグが体になじまない次の判定の成功段階がー1される。',
  145. '乱闘:不良との喧嘩に巻き込まれた。PC は1d10 点のダメージを受ける。',
  146. '大人:悪辣な大人に遭遇して怒りが募る。PC は不良度が1d10 点上昇する',
  147. '仲違い:つまらないことで喧嘩になって友情に亀裂が入る。場面に登場している【関係】を結んでいるキャラクターの中からランダムに対象を1 人選ぶ。シナリオが終了するまで対象との【関係】が失われる。',
  148. '悪名:ボスの悪名が広がることによって自然とボスの取り巻きが増える。次の戦闘フェイズにモブが敵として1 人参加する。モブの種類はGM が決定する。',
  149. '凶暴化:ボスの思考が先鋭化して凶悪になる。シナリオが終了するまでボスが与えるダメージを+2 する。この効果は累積するが、上昇した能力値は戦力には影響しない。',
  150. '警戒:ボスは自身の周りでうごめく不穏な気配に警戒を強める。ボスの【HP 最大値】と【HP 現在値】を+10 する。この効果は累積する。',
  151. '不運:ツキがなくなってきた気がする...。ラッキーナンバーの数値が2下がる(最低1)。すでにラッキーナンバーを使用済みであれば効果を受けない。'
  152. ]
  153. ),
  154. 'DT' => DiceTable::Table.new(
  155. '闇堕ち表',
  156. '1D10',
  157. [
  158. '出奔:すべての人間関係を捨ててどこか遠くへ旅に出る。',
  159. '半グレ:半グレ集団とつるむようになり、悪事に手を染めるようになる。',
  160. '指名手配:重大な犯罪を起こして指名手配されて逃亡者となる。',
  161. '事故:大事故に遭い意識不明の重体となり長期入院する。',
  162. 'ヤク中:薬物中毒者となり、薬を得るためなら何でもするようになる。',
  163. '借金:イカれた人間を信奉するようになり多額の借金を背負わされる。',
  164. '傀儡:悪意を持って人間を利用しようとする勢力に祭り上げられ傀儡と化す。',
  165. '身代わり:犯罪を犯した人間の身代わりにされて追われる身となる。',
  166. '逮捕:度を越えた暴力沙汰を度々起こして警察に逮捕される。',
  167. '失踪:ヤバい事件に首を突っ込んで謎の失踪を遂げる。'
  168. ]
  169. )
  170. }.freeze
  171. 1 register_prefix('YD', TABLES.keys)
  172. end
  173. end
  174. end

lib/bcdice/game_system/YankeeYogSothoth.rb

100.0% lines covered

83.33% branches covered

27 relevant lines. 27 lines covered and 0 lines missed.
6 total branches, 5 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/dice_table/table"
  3. 1 require "bcdice/dice_table/d66_table"
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class YankeeYogSothoth < Base
  7. # ゲームシステムの識別子
  8. 1 ID = 'YankeeYogSothoth'
  9. # ゲームシステム名
  10. 1 NAME = 'ヤンキー&ヨグ=ソトース'
  11. # ゲームシステム名の読みがな
  12. 1 SORT_KEY = 'やんきいあんとよくそとおす'
  13. # ダイスボットの使い方
  14. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  15. ・判定
  16. スペシャル/ファンブル/成功/失敗を判定
  17. ・各種表
  18. ※うろつき~決闘フェイズ
  19. FT ファンブル表
  20. WT 変調表
  21. RTTn ランダム特技決定表(n:分野番号、省略可能)
  22. RCT ランダム分野決定表
  23. KKT 関係表
  24. DBRT 他愛のない会話表
  25. TKT 戦う理由表
  26. ※武勇伝フェイズ
  27. BUDT 武勇伝表
  28. GUDT ガイヤンキー武勇伝表
  29. FTNT 二つ名決定表
  30. DAIT 第一印象表
  31. TKKT ツレ関係表
  32. ※帰還フェイズ
  33. GSST 現実世界生活表
  34. GYST ガイヤンキー生活表
  35. HPST 病院生活表
  36. ・D66ダイスあり
  37. INFO_MESSAGE_TEXT
  38. 1 def initialize(command)
  39. 52 super(command)
  40. 52 @d66_sort_type = D66SortType::ASC
  41. end
  42. # ゲーム別成功度判定(2D6)
  43. 1 def result_2d6(_total, dice_total, _dice_list, cmp_op, _target)
  44. 5 else: 5 then: 0 return nil unless cmp_op == :>=
  45. 5 then: 1 if dice_total <= 2
  46. 1 else: 4 Result.fumble("ファンブル(判定失敗。ファンブル表(FT)を振ること)")
  47. 4 then: 1 else: 3 elsif dice_total >= 12
  48. 1 Result.critical("スペシャル(判定成功。【テンション】が1段階上昇)")
  49. end
  50. end
  51. 1 def eval_game_system_specific_command(command)
  52. 47 roll_tables(command, TABLES) || RTT.roll_command(randomizer, command)
  53. end
  54. 1 NICKNAME_TABLE1 = DiceTable::D66Table.new(
  55. '二つ名表1',
  56. D66SortType::ASC,
  57. {
  58. 11 => '「愛死天流(あいしてる)」',
  59. 12 => '「喧嘩上等(けんかじょうとう)」',
  60. 13 => '「正々堂々(せいせいどうどう)」',
  61. 14 => '「天下無敵(てんかむてき)」',
  62. 15 => '「一騎当千(いっきとうせん)」',
  63. 16 => '「威風堂々(いふうどうどう)」',
  64. 22 => '「焼肉定食(やきにくていしょく)」',
  65. 23 => '「完全無欠(かんぜんむけつ)」',
  66. 24 => '「獅子奮迅(ししふんじん)」',
  67. 25 => '「臥薪嘗胆(がしんしょうたん)」',
  68. 26 => '「疾風迅雷(しっぷうじんらい)」',
  69. 33 => '「夜露死苦(よろしく)」',
  70. 34 => '「天上天下(てんじょうてんげ)」',
  71. 35 => '「唯我独尊(ゆいがどくそん)」',
  72. 36 => '「電光石火(でんこうせっか)」',
  73. 44 => '「仏恥義理(ぶっちぎり)」',
  74. 45 => '「百戦百勝(ひゃくせんひゃくしょう)」',
  75. 46 => '「百戦錬磨(ひゃくせんれんま)」',
  76. 55 => '「残酷非道(ざんこくひどう)」',
  77. 56 => '「一意専心(いちいせんしん)」',
  78. 66 => '「時給千円(じきゅうせんえん)」'
  79. }
  80. )
  81. 1 NICKNAME_TABLE2 = DiceTable::D66Table.new(
  82. '二つ名表2',
  83. D66SortType::ASC,
  84. {
  85. 11 => '「みんなの」',
  86. 12 => '「スルー推奨」',
  87. 13 => '「暴れん坊」',
  88. 14 => '「仲間思い」',
  89. 15 => '「サボり魔」',
  90. 16 => '「熱血番長の」',
  91. 22 => '「今日がダメでも明日がある」',
  92. 23 => '「すぐカッとなる」',
  93. 24 => '「夢を応援する」',
  94. 25 => '「地元じゃ有名な」',
  95. 26 => '「喧嘩慣れている」',
  96. 33 => '「いつかビックになる」',
  97. 34 => '「いいやつの」',
  98. 35 => '「意外とまじめな」',
  99. 36 => '「イイ感じの」',
  100. 44 => '「家族想いの」',
  101. 45 => '「とにかくモテる」',
  102. 46 => '「学校を代表するワル」',
  103. 55 => '「邪神ハンター」',
  104. 56 => '「男前/イイ女」',
  105. 66 => '「悪そうなやつはだいたい友達」'
  106. }
  107. )
  108. 1 NICKNAME_TABLE3 = DiceTable::D66Table.new(
  109. '二つ名表3',
  110. D66SortType::ASC,
  111. {
  112. 11 => '「ファッションヤンキー」',
  113. 12 => '「誰もが知っている」',
  114. 13 => '「チャラい」',
  115. 14 => '「ツヨメ」',
  116. 15 => '「中学時代はすごかった」',
  117. 16 => '「イカれたやつ」',
  118. 22 => '「道徳の授業で泣いた」',
  119. 23 => '「マジか」',
  120. 24 => '「イケイケ」',
  121. 25 => '「鬼語り」',
  122. 26 => '「とりま」',
  123. 33 => '「ちょっと眠たい」',
  124. 34 => '「パネエ」',
  125. 35 => '「エモい」',
  126. 36 => '「やべーぞ!」',
  127. 44 => '「お腹が減っている」',
  128. 45 => '「むっつりスケベの」',
  129. 46 => '「いじわるな」',
  130. 55 => '「全国区に報道された」',
  131. 56 => '「毎日が楽しい」',
  132. 66 => '「おやじ狩り狩り」'
  133. }
  134. )
  135. 1 NICKNAME_TABLE4 = DiceTable::D66Table.new(
  136. '二つ名表4',
  137. D66SortType::ASC,
  138. {
  139. 11 => '「国産」',
  140. 12 => '「ブレブレ」',
  141. 13 => '「ロボ」',
  142. 14 => '「大銀河」',
  143. 15 => '「超獣」',
  144. 16 => '「ミステリー」',
  145. 22 => '「超電磁」',
  146. 23 => '「危険な」',
  147. 24 => '「湯上がり」',
  148. 25 => '「すごい」',
  149. 26 => '「エロ」',
  150. 33 => '「福岡」',
  151. 34 => '「エリート」',
  152. 35 => '「どんまい」',
  153. 36 => '「がり勉」',
  154. 44 => '「東京」',
  155. 45 => '「スペース」',
  156. 46 => '「永遠の」',
  157. 55 => '「大阪」',
  158. 56 => '「輝け!」',
  159. 66 => '「名古屋」'
  160. }
  161. )
  162. 1 RTT = DiceTable::SaiFicSkillTable.new(
  163. [
  164. ['苦手', ['大人', '勉強', '敗北', '昆虫', '親', '異性', '孤独', '高所', '暗がり', 'ホラー', '子供']],
  165. ['部活', ['柔道', 'プロレス', 'テコンドー', '空手', 'ボクシング', '帰宅', '剣道', '野球', '応援団', '科学', '文系']],
  166. ['中学時代', ['悪ガキ', '統一', 'バイト', '習い事', '喧嘩', 'サボり', 'マジメくん', '遊び歩き', '真似ごと', '部活', '何もしない']],
  167. ['趣味', ['すけべ', '車・バイク', '家事', '料理', '運動', '修行', 'ファッション', 'つるむ', '寝る', 'ゲーム', '読書']],
  168. ['スタイル', ['テキトー', 'ばか', 'オラオラ', '熱血', '硬派', '自然体', '軟派', '自分大好き', '腹黒', 'クール', 'インテリ']],
  169. ['好み', ['だらだら', '食事', '逆転', '家族', '支配', '褒められる', '恋愛', '友情', '勝利', '金', '静寂']],
  170. ],
  171. rtt_format: "ランダム指定特技表(%<category_dice>d,%<row_dice>d) > %<text>s"
  172. )
  173. TABLES = {
  174. 1 "FTNT" => DiceTable::ChainTable.new(
  175. "二つ名決定表",
  176. "1D6",
  177. [
  178. NICKNAME_TABLE1,
  179. NICKNAME_TABLE1,
  180. NICKNAME_TABLE2,
  181. NICKNAME_TABLE2,
  182. NICKNAME_TABLE3,
  183. NICKNAME_TABLE4,
  184. ]
  185. ),
  186. "FT" => DiceTable::Table.new(
  187. "ファンブル表",
  188. "1D6",
  189. [
  190. 'やっちまった……。テンションが1段階減少する。',
  191. 'ひょうなことから嫌な状況になる。ランダムに変調(WT)を1つ受ける。',
  192. 'あまりにもカッコ悪いところが伝わってしまう。自分に対して【友情度】を持つPC全員は、リスペクトにチェックを入れる。',
  193. '自分の絶望を観測し、邪神が活性化する。バッドヤンキーの「ケツモチ邪神の加護」が1点上昇する。',
  194. 'つまらないことで怪我をする。自分の【HP】が1D6点減少する。',
  195. '逆境に燃える。テンションが1段階上昇する。'
  196. ]
  197. ),
  198. "WT" => DiceTable::Table.new(
  199. "変調表",
  200. "1D6",
  201. [
  202. '毒:サイクル終了時もしくはラウンド終了時に、2D6点のダメージを受ける。',
  203. '呪い:熱血蘇生の達成値が2点減少する。NPCが受けた場合、受けるダメージが2点上昇する。',
  204. '火傷:テンションの効果によって、【攻撃力】が上昇しない。NPCは【攻撃力】が2点低いものとして扱う(最低0点)。',
  205. '骨折:判定に失敗するたびに、5点のダメージを受ける。',
  206. '出血:サイクル終了時もしくはラウンド終了時に、2点のダメージを受ける。また、施設やアイテムの効果で【HP】が上昇しない。',
  207. '目つぶし:判定の達成値が2点減少する。'
  208. ]
  209. ),
  210. "KKT" => DiceTable::Table.new(
  211. "関係表",
  212. "1D6",
  213. ['「家族/気に食わない」', '「親友/近寄るな」', '「悪友/こざかしい」', '「ライバル/チンピラ」', '「いい奴/悪い奴」', '「利用できる/ヘタレ」']
  214. ),
  215. "DBRT" => DiceTable::D66Table.new(
  216. "他愛のない会話表",
  217. :asc,
  218. {
  219. 11 => "「政治の話」",
  220. 12 => "「勉強の話」",
  221. 13 => "「友達の話」",
  222. 14 => "「兄弟姉妹の話」",
  223. 15 => "「好きなものの話」",
  224. 16 => "「嫌いなものの話」",
  225. 22 => "「ラーメンの話」",
  226. 23 => "「コンビニの話」",
  227. 24 => "「学校生活の話」",
  228. 25 => "「先輩後輩の話」",
  229. 26 => "「趣味の話」",
  230. 33 => "「肉の話」",
  231. 34 => "「中学時代の話」",
  232. 35 => "「喧嘩の話」",
  233. 36 => "「ファッションの話」",
  234. 44 => "「家の話」",
  235. 45 => "「好みの異性の話」",
  236. 46 => "「テレビ番組の話」",
  237. 55 => "「野菜の話」",
  238. 56 => "「部活の話」",
  239. 66 => "「ダブりの話」",
  240. }
  241. ),
  242. "TKT" => DiceTable::D66Table.new(
  243. "戦う理由表",
  244. :asc,
  245. {
  246. 11 => "「なんとなく」",
  247. 12 => "「好みのエルフがいた」",
  248. 13 => "「エルフに世話になった」",
  249. 14 => "「ドワーフの飯がうまかった」",
  250. 15 => "「ドワーフにファッション特徴を作ってもらった」",
  251. 16 => "「妖精たちのいたずらがほほえましかった」",
  252. 22 => "「バッドヤンキーと昔からの因縁があるから」",
  253. 23 => "「バッドヤンキーが気に入らなかった」",
  254. 24 => "「強いやつと戦いたい」",
  255. 25 => "「異世界にワクワクしているから」",
  256. 26 => "「バッドヤンキー集団に迷惑を受けたから」",
  257. 33 => "「夢見るNPCが好みだったから」",
  258. 34 => "「夢見るNPCの夢に共感したから」",
  259. 35 => "「夢見るNPCの夢を応援したいと思ったから」",
  260. 36 => "「夢見るNPCを放っておけないから」",
  261. 44 => "「家に帰りたいから」",
  262. 45 => "「夢見るNPCは友達だから」",
  263. 46 => "「他のPCと気が合ったから」",
  264. 55 => "「マーメイドと仲良くなった」",
  265. 56 => "「退屈を紛らわせられそうだから」",
  266. 66 => "「ただ暴れたかった」",
  267. }
  268. ),
  269. "BUDT" => DiceTable::D66Table.new(
  270. "武勇伝表",
  271. :asc,
  272. {
  273. 11 => "バッドヤンキーのチームに自分が所属する学校を破壊されたが、最後まで戦った。/テンションが1段階上昇",
  274. 12 => "バッドヤンキーチームの兵隊が襲い掛かってきたが、撃退した。/【HP】+3",
  275. 13 => "バッドヤンキーと何度も戦い、ライバルとして認識されていた。/【打たれ強さ】+1",
  276. 14 => "バッドヤンキー配下の集団をいくつか潰してまわっていた。/【攻撃力】+1",
  277. 15 => "バッドヤンキーのチームに入りそうになった後輩を説得した。/【HP】+3",
  278. 16 => "バッドヤンキーに支配されていた店を救った。/【攻撃力】+1",
  279. 22 => "アメリカで暴れた。/テンションが1段階上昇",
  280. 23 => "学校をサボって、日本全国を旅をしてまわった。/【HP】+3",
  281. 24 => "好きなアーティストのライブに行き、マナーの悪いファンを黙らせた。/【打たれ強さ】+1",
  282. 25 => "抗争中の学校に一人で乗り込んで、戦いを終わらせた。/【攻撃力】+1",
  283. 26 => "へまをした仲間を助けるため、頭を下げた。/【HP】+3",
  284. 33 => "大規模な運動会で活躍し、最優秀賞を獲得した。/【攻撃力】+1",
  285. 34 => "家族や仲間に迷惑をかけたチームを潰した。/【打たれ強さ】+1",
  286. 35 => "暴走族を一人で潰した。/【攻撃力】+1",
  287. 36 => "本職(ヤクザ)と戦って謝らせた。/【打たれ強さ】+1",
  288. 44 => "ドッジボール大会に出場し、優勝をして賞品を手に入れた。/「絆創膏」「テンアゲアイテム」「ポーション」「お守り」のうち1つを選んで獲得する",
  289. 45 => "仲間たちと一緒に学校行事を盛り上げた。/【打たれ強さ】+1",
  290. 46 => "仲間と一緒にディスカウントストアで買い物をし、キャンプをした。/「絆創膏」「テンアゲアイテム」「ポーション」「お守り」のうち1つを選んで獲得する",
  291. 55 => "隣のプレイヤーのPCが所属する高校と大きな抗争をした。/右隣のプレイヤーのPCに対する【友情度】が1点上昇",
  292. 56 => "修学旅行先で喧嘩し、その後友情を深めた。/【攻撃力】+1",
  293. 66 => "隣のプレイヤーのPCと一緒に、大きな悪の組織を潰した。/右隣のプレイヤーのPCに対する【友情度】が1点上昇",
  294. }
  295. ),
  296. "GUDT" => DiceTable::D66Table.new(
  297. "ガイヤンキー武勇伝表",
  298. :asc,
  299. {
  300. 11 => "アザトースが突然接触してきたので、殴って追い返した。/テンションが1段階上昇",
  301. 12 => "シュブ=ニグラスのサバトに乗り込んで潰した。/【HP】+3",
  302. 13 => "クトゥルフの落とし子を殴り倒して追い返した。/【打たれ強さ】+1",
  303. 14 => "ヨグ=ソトースの勧誘を受けたが、断ってやった。/【攻撃力】+1",
  304. 15 => "深きものどもが住む漁村を訪ね、罠にはめられたが脱出した。/【HP】+3",
  305. 16 => "一晩飲み明かした相手がナイアーラトテップだった。/【攻撃力】+1",
  306. 22 => "生きてる恐竜と出会った。/テンションが1段階上昇",
  307. 23 => "ファンタジー世界を冒険者として旅してまわった。/【HP】+3",
  308. 24 => "町で起こった少女たちの失踪事件を解決した。/【打たれ強さ】+1",
  309. 25 => "バッドヤンキーに潰された騎士団を鼓舞して、立て直しに協力した。/【攻撃力】+1",
  310. 26 => "大きな城下町に起こった殺人事件や傷害事件を幾つも解決した。/【HP】+3",
  311. 33 => "大きな城下町で、テンションが上がっていろいろ買い込んでしまった。/「絆創膏」「テンアゲアイテム」「ポーション」「お守り」のうち1つを選んで獲得する",
  312. 34 => "エルフの森を燃やしつくそうとする拝火暴走族をこらしめた。/【打たれ強さ】+1",
  313. 35 => "ドワーフの洞窟に現われた巨大ワームを投げ飛ばした。/【攻撃力】+1",
  314. 36 => "妖精たちの村に迷い込んで、村を荒らそうとするゴブリンをブッ飛ばした。/【打たれ強さ】+1",
  315. 44 => "巨大な王国が主催している武術大会で優勝し、名誉とアイテムを手に入れた。/「絆創膏」「テンアゲアイテム」「ポーション」「お守り」のうち1つを選んで獲得する",
  316. 45 => "ゴブリンの襲撃から町を守り切った。/【打たれ強さ】+1",
  317. 46 => "悪いチームにさらわれた姫や王子様を助けたら、惚れられた。/【攻撃力】+1",
  318. 55 => "次に会うヤンキーのために、この世界の土産話を作ってきた。/右隣のプレイヤーのPCに対する【友情度】が1点上昇",
  319. 56 => "悪い魔法使いの儀式を突き止めて、潰した。/【攻撃力】+1",
  320. 66 => "次に会うヤンキーのために、うまいものを用意した。/右隣のプレイヤーのPCに対する【友情度】が1点上昇",
  321. }
  322. ),
  323. "DAIT" => DiceTable::Table.new(
  324. "第一印象表",
  325. "1D6",
  326. ['「ヤベエ」', '「パネエ」', '「スゲエ」', '「びっくり」', '「たばい」', '「アウトオブ眼中」']
  327. ),
  328. "TKKT" => DiceTable::Table.new(
  329. "ツレ関係表",
  330. "1D6",
  331. ['「すごそう」', '「勇者様」', '「つよい」', '「いい人」', '「かっこいい」', '「利用できる」']
  332. ),
  333. "GSST" => DiceTable::D66Table.new(
  334. "現実世界生活表",
  335. :asc,
  336. {
  337. 11 => "喧嘩に明け暮れた",
  338. 12 => "真面目に授業を受けた",
  339. 13 => "今回の仲間と食事をしに行った",
  340. 14 => "チーム同士の抗争を沈めた",
  341. 15 => "ぼーっとしていた",
  342. 16 => "バイトに専念した",
  343. 22 => "仲間とバーベキューをした",
  344. 23 => "自分の体を鍛えることにした",
  345. 24 => "仲間との毎日をより大切にした",
  346. 25 => "家族とゆっくりすごした",
  347. 26 => "喧嘩の技術を磨いた",
  348. 33 => "本職(ヤクザ)と喧嘩をした",
  349. 34 => "好きなだけ寝た",
  350. 35 => "ツレができた",
  351. 36 => "今回の仲間と旅に出た",
  352. 44 => "異性と遊園地に行くことになった",
  353. 45 => "あの戦いの日々を思い返していた",
  354. 46 => "次の戦いに備えた",
  355. 55 => "運動部の助っ人として、大会に出た",
  356. 56 => "好きなだけ好物を食べた",
  357. 66 => "汚い大人の罠にはめられたが、なんとかした",
  358. }
  359. ),
  360. "GYST" => DiceTable::D66Table.new(
  361. "ガイヤンキー生活表",
  362. :asc,
  363. {
  364. 11 => "ツレと生活をした",
  365. 12 => "異世界について学んだ",
  366. 13 => "エルフの美形(平均年齢200歳)に接待を受けた",
  367. 14 => "ドワーフから地元の酒をもらった",
  368. 15 => "妖精の村に迷い込んでしまった",
  369. 16 => "この世界の遺跡を回った",
  370. 22 => "この世界に野球などのスポーツを広めた",
  371. 23 => "広大な森の中で迷ってしまい、数か月ほどサバイバルした",
  372. 24 => "不思議な力が溢れる泉の水を飲み干した",
  373. 25 => "魔法使いの研究に協力したが、さっぱりだった",
  374. 26 => "ハーピィに誘われて空の旅を満喫した",
  375. 33 => "この世界にヤンキー文化を伝えた",
  376. 34 => "バッドヤンキーに荒らされた小さな村を復興した",
  377. 35 => "悪徳領主にさらわれた少女を助けた",
  378. 36 => "わるい商人を殴り飛ばした",
  379. 44 => "エルフの漫画家が誕生するのを見届けた",
  380. 45 => "巨大なドラゴンと殴りあって勝利した",
  381. 46 => "海中に住むマーメイドを脅かす悪人を退治した",
  382. 55 => "邪神を信奉している神殿に殴り込みをして、企みを阻止した",
  383. 56 => "天使っぽいのが悪いことをしていたので蹴り飛ばした",
  384. 66 => "農作業をした",
  385. }
  386. ),
  387. "HPST" => DiceTable::D66Table.new(
  388. "病院生活表",
  389. :asc,
  390. {
  391. 11 => "治療に専念した",
  392. 12 => "見舞いでもらった漫画を読み倒した",
  393. 13 => "ゲームをひたすらやった",
  394. 14 => "悪化した病と闘った",
  395. 15 => "入院している子供と約束をした",
  396. 16 => "看護師と仲良くなった",
  397. 22 => "現代の医術では治療できなかったので、異世界の魔法に賭けた",
  398. 23 => "院内パーティを盛り上げた",
  399. 24 => "飯がまずくて苦労した",
  400. 25 => "飯がうまくて感動をした",
  401. 26 => "やることがなくて暇だった",
  402. 33 => "スーパードクターが現われて、自分の怪我を見事に治してくれた",
  403. 34 => "とにかくテレビを見続けて、知識がついた",
  404. 35 => "勉強をしてみたら、いつも以上にはかどった",
  405. 36 => "たくさんの人たちが見舞いに来て、感動した",
  406. 44 => "入院をしている爺さんから色々教えてもらった",
  407. 45 => "リハビリに思ったより時間がかかった",
  408. 46 => "次に喧嘩するときのイメージトレーニングをした",
  409. 55 => "ヤンキー漫画に感動をした",
  410. 56 => "院内で喧嘩をした",
  411. 66 => "売店で売っているお菓子をコンプリートした",
  412. }
  413. ),
  414. }.freeze
  415. 1 register_prefix(RTT.prefixes, TABLES.keys)
  416. end
  417. end
  418. end

lib/bcdice/game_system/YearZeroEngine.rb

95.67% lines covered

78.38% branches covered

208 relevant lines. 199 lines covered and 9 lines missed.
74 total branches, 58 branches covered and 16 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class YearZeroEngine < Base
  5. # ゲームシステムの識別子
  6. 1 ID = 'YearZeroEngine'
  7. # ゲームシステム名
  8. 1 NAME = 'YearZeroEngine'
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = 'いやあせろえんしん'
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ・ダイスプール判定コマンド(nYZEx+x+x+m)
  14. (難易度)YZE(能力ダイス数)+(技能ダイス数)+(アイテムダイス数)+(修正値) # (6のみを数える)
  15. (難易度)YZE(能力ダイス数)+(技能ダイス数)+(アイテムダイス数)-(修正値) # (6のみを数える)
  16. ・ダイスプール判定コマンド(nMYZx+x+x)
  17. (難易度)MYZ(能力ダイス数)+(技能ダイス数)+(アイテムダイス数) # (1と6を数え、プッシュ可能数を表示)
  18. (難易度)MYZ(能力ダイス数)-(技能ダイス数)+(アイテムダイス数) # (1と6を数え、プッシュ可能数を表示、技能のマイナス指定)
  19. ※ 難易度と技能、アイテムダイス数は省略可能
  20. ・ステップダイス判定コマンド(nYZSx+x+m+f)
  21. (難易度)YZS(能力ダイス面数)+(技能ダイス面数)+(修正値) # (1,6を数え、プッシュ可能数を表示)
  22. (難易度)YZS(能力ダイス面数)+(技能ダイス面数)-(修正値) # (1,6を数え、プッシュ可能数を表示)
  23. (難易度)YZS(能力ダイス面数)+(技能ダイス面数)+(修正値)A # (1,6を数え、プッシュ可能数を表示、有利)
  24. (難易度)YZS(能力ダイス面数)+(技能ダイス面数)-(修正値)A # (1,6を数え、プッシュ可能数を表示、有利)
  25. (難易度)YZS(能力ダイス面数)+(技能ダイス面数)+(修正値)D # (1,6を数え、プッシュ可能数を表示、不利)
  26. (難易度)YZS(能力ダイス面数)+(技能ダイス面数)-(修正値)D # (1,6を数え、プッシュ可能数を表示、不利)
  27. INFO_MESSAGE_TEXT
  28. 1 DIFFICULTY_INDEX = 1 # 難易度のインデックス
  29. 1 COMMAND_TYPE_INDEX = 2 # コマンドタイプのインデックス
  30. 1 ABILITY_INDEX = 3 # 能力値ダイスのインデックス
  31. 1 SKILL_SIGNED_INDEX = 5 # 技能値ダイス符号のインデックス
  32. 1 SKILL_INDEX = 6 # 技能値ダイスのインデックス
  33. 1 GEAR_INDEX = 8 # アイテムダイスのインデックス
  34. 1 MODIFIER_SIGNED_INDEX = 10 # 修正値の符号のインデックス
  35. 1 MODIFIER_INDEX = 11 # 修正値のインデックス
  36. 1 register_prefix('(\d+)?(YZE|MYZ|YZS)')
  37. 1 def dice_info_init()
  38. 90 @total_success_dice = 0
  39. 90 @total_botch_dice = 0
  40. 90 @base_botch_dice = 0
  41. 90 @skill_botch_dice = 0
  42. 90 @gear_botch_dice = 0
  43. 90 @push_dice = 0
  44. 90 @difficulty = 0
  45. end
  46. 1 def eval_game_system_specific_command(command)
  47. 90 resolute_action(command) ||
  48. resolute_push_action(command) ||
  49. resolute_step_action(command)
  50. end
  51. 1 def resolute_action(command)
  52. 90 m = /\A(\d+)?(YZE)(\d+)((\+)(\d+))?(\+(\d+))?((\+|-)(\d+))?/.match(command)
  53. 90 else: 36 then: 54 unless m
  54. 54 return nil
  55. end
  56. 36 dice_info_init
  57. 36 @difficulty = m[DIFFICULTY_INDEX].to_i
  58. 36 attribute = m[ABILITY_INDEX].to_i
  59. 36 skill = m[SKILL_INDEX].to_i
  60. 36 gear = m[GEAR_INDEX].to_i
  61. 36 modifier = m[MODIFIER_INDEX].to_i
  62. 36 then: 3 if m[MODIFIER_SIGNED_INDEX] == '-'
  63. 3 then: 1 if skill >= modifier
  64. 1 skill -= modifier
  65. else: 2 else
  66. 2 modifier -= skill
  67. 2 skill = 0
  68. 2 then: 1 if gear >= modifier
  69. 1 gear -= modifier
  70. else: 1 else
  71. 1 modifier -= gear
  72. 1 gear = 0
  73. 1 then: 1 if attribute >= modifier
  74. 1 attribute -= modifier
  75. else: 0 else
  76. attribute = 0
  77. end
  78. end
  79. end
  80. else: 33 else
  81. 33 skill += modifier
  82. end
  83. 36 @total_success_dice = 0
  84. 36 dice_pool = attribute
  85. 36 ability_dice_text, success_dice, botch_dice = make_dice_roll(dice_pool)
  86. 36 @total_success_dice += success_dice
  87. 36 @total_botch_dice += botch_dice
  88. 36 @base_botch_dice += botch_dice # 能力ダメージ
  89. 36 @push_dice += (dice_pool - (success_dice + botch_dice))
  90. 36 dice_count_text = "(#{dice_pool}D6)"
  91. 36 dice_text = ability_dice_text
  92. 36 then: 28 else: 8 if m[SKILL_INDEX]
  93. 28 dice_pool = skill
  94. 28 skill_dice_text, success_dice, botch_dice = make_dice_roll(dice_pool)
  95. 28 @total_success_dice += success_dice
  96. 28 @total_botch_dice += botch_dice
  97. 28 @skill_botch_dice += botch_dice # 技能ダイスの1はpushで振り直し可能(例えマイナス技能でも)
  98. 28 @push_dice += (dice_pool - success_dice) # 技能ダイスのみ1を含むので、ここでは1を計算に入れない
  99. 28 dice_count_text += "+(#{dice_pool}D6)"
  100. 28 dice_text += "+#{skill_dice_text}"
  101. end
  102. 36 then: 20 else: 16 if m[GEAR_INDEX]
  103. 20 dice_pool = gear
  104. 20 gear_dice_text, success_dice, botch_dice = make_dice_roll(dice_pool)
  105. 20 @total_success_dice += success_dice
  106. 20 @total_botch_dice += botch_dice
  107. 20 @gear_botch_dice += botch_dice # ギアダメージ
  108. 20 @push_dice += (dice_pool - (success_dice + botch_dice))
  109. 20 dice_count_text += "+(#{dice_pool}D6)"
  110. 20 dice_text += "+#{gear_dice_text}"
  111. end
  112. 36 return make_result_with_yze(dice_count_text, dice_text)
  113. end
  114. 1 def resolute_push_action(command)
  115. 54 m = /\A(\d+)?(MYZ)(\d+)((\+|-)(\d+))?(\+(\d+))?/.match(command)
  116. 54 else: 42 then: 12 unless m
  117. 12 return nil
  118. end
  119. 42 dice_info_init
  120. 42 @difficulty = m[DIFFICULTY_INDEX].to_i
  121. 42 @total_success_dice = 0
  122. 42 dice_pool = m[ABILITY_INDEX].to_i
  123. 42 ability_dice_text, success_dice, botch_dice = make_dice_roll(dice_pool)
  124. 42 @total_success_dice += success_dice
  125. 42 @total_botch_dice += botch_dice
  126. 42 @base_botch_dice += botch_dice # 能力ダメージ
  127. 42 @push_dice += (dice_pool - (success_dice + botch_dice))
  128. 42 dice_count_text = "(#{dice_pool}D6)"
  129. 42 dice_text = ability_dice_text
  130. 42 then: 34 else: 8 if m[SKILL_INDEX]
  131. 34 dice_pool = m[SKILL_INDEX].to_i
  132. 34 skill_dice_text, success_dice, botch_dice = make_dice_roll(dice_pool)
  133. 34 skill_unsigned = m[SKILL_SIGNED_INDEX]
  134. 34 then: 9 if skill_unsigned == '-'
  135. 9 @total_success_dice -= success_dice # マイナス技能の成功は通常の成功と相殺される
  136. else: 25 else
  137. 25 @total_success_dice += success_dice
  138. end
  139. 34 @total_botch_dice += botch_dice
  140. 34 @skill_botch_dice += botch_dice # 技能ダイスの1はpushで振り直し可能(例えマイナス技能でも)
  141. 34 @push_dice += (dice_pool - success_dice) # 技能ダイスのみ1を含むので、ここでは1を計算に入れない
  142. 34 dice_count_text += "#{skill_unsigned}(#{dice_pool}D6)"
  143. 34 dice_text += "#{skill_unsigned}#{skill_dice_text}"
  144. end
  145. 42 then: 22 else: 20 if m[GEAR_INDEX]
  146. 22 dice_pool = m[GEAR_INDEX].to_i
  147. 22 gear_dice_text, success_dice, botch_dice = make_dice_roll(dice_pool)
  148. 22 @total_success_dice += success_dice
  149. 22 @total_botch_dice += botch_dice
  150. 22 @gear_botch_dice += botch_dice # ギアダメージ
  151. 22 @push_dice += (dice_pool - (success_dice + botch_dice))
  152. 22 dice_count_text += "+(#{dice_pool}D6)"
  153. 22 dice_text += "+#{gear_dice_text}"
  154. end
  155. 42 return make_result_with_myz(dice_count_text, dice_text)
  156. end
  157. 1 def make_result_with_yze(dice_count_text, dice_text)
  158. 36 result_text = "#{dice_count_text} > #{dice_text} 成功数:#{@total_success_dice}"
  159. 36 then: 16 else: 20 if @difficulty > 0
  160. 16 then: 9 if @total_success_dice >= @difficulty
  161. 9 return Result.success("#{result_text} 難易度=#{@difficulty}:判定成功!")
  162. else: 7 else
  163. 7 return Result.failure("#{result_text} 難易度=#{@difficulty}:判定失敗!")
  164. end
  165. end
  166. 20 return result_text
  167. end
  168. 1 def make_result_with_myz(dice_count_text, dice_text)
  169. 54 result_text = "#{dice_count_text} > #{dice_text} 成功数:#{@total_success_dice}"
  170. 54 atter_text = "\n出目1:[能力:#{@base_botch_dice},技能:#{@skill_botch_dice},アイテム:#{@gear_botch_dice}) プッシュ可能=#{@push_dice}ダイス"
  171. 54 then: 24 else: 30 if @difficulty > 0
  172. 24 then: 12 if @total_success_dice >= @difficulty
  173. 12 return Result.success("#{result_text} 難易度=#{@difficulty}:判定成功!#{atter_text}")
  174. else: 12 else
  175. 12 return Result.failure("#{result_text} 難易度=#{@difficulty}:判定失敗!#{atter_text}")
  176. end
  177. end
  178. 30 return "#{result_text}#{atter_text}"
  179. end
  180. 1 def make_dice_roll(dice_pool)
  181. 182 dice_list = @randomizer.roll_barabara(dice_pool, 6)
  182. 182 success_dice = dice_list.count(6)
  183. 182 botch_dice = dice_list.count(1)
  184. 182 return "[#{dice_list.join(',')}]", success_dice, botch_dice
  185. end
  186. 1 def make_dice_a_roll(count, type)
  187. 20 dice_list = @randomizer.roll_barabara(count, type)
  188. 20 botch_dice = dice_list.count(1)
  189. 42 success_dice = dice_list.count { |val| val >= 6 }
  190. 42 success_level = success_dice + dice_list.count { |val| val >= 10 }
  191. 20 @total_success_dice += success_level
  192. 20 @total_botch_dice += botch_dice
  193. 20 @push_dice += (count - (success_dice + botch_dice))
  194. 20 return "[#{dice_list.join(',')}]", botch_dice
  195. end
  196. 1 def get_rolling_dice(dice_type1, dice_type2, dice_upgrade)
  197. 12 then: 0 else: 12 dice_type1 = 4 if dice_type1 < 4
  198. 12 then: 1 else: 11 dice_type2 = 4 if dice_type2 < 4
  199. 12 body: 1 while dice_upgrade > 0
  200. 1 then: 1 if dice_type1 >= dice_type2
  201. 1 then: 1 else: 0 dice_type2 += 2 if dice_type2 < 12
  202. else: 0 else
  203. then: 0 else: 0 dice_type1 += 2 if dice_type1 < 12
  204. end
  205. 1 dice_upgrade -= 1
  206. end
  207. 12 body: 1 while dice_upgrade < 0
  208. 1 then: 1 if dice_type1 <= dice_type2
  209. 1 then: 1 else: 0 dice_type2 -= 2 if dice_type2 > 4
  210. else: 0 else
  211. then: 0 else: 0 dice_type1 -= 2 if dice_type1 > 4
  212. end
  213. 1 dice_upgrade += 1
  214. end
  215. 12 then: 0 else: 12 if dice_type1 == 4 && dice_type2 == 4
  216. dice_type1 = 6
  217. end
  218. 12 return dice_type1, dice_type2
  219. end
  220. 1 def resolute_step_action(command)
  221. 12 m = /\A(\d+)?(YZS)(\d+)((\+)(\d+))?((\+|-)(\d+))?(A|D)?/.match(command)
  222. 12 else: 12 then: 0 unless m
  223. return nil
  224. end
  225. 12 dice_info_init
  226. 12 @difficulty = m[DIFFICULTY_INDEX].to_i
  227. 12 attribute = m[ABILITY_INDEX].to_i
  228. 12 skill = m[SKILL_INDEX].to_i
  229. 12 modifier = m[7].to_i
  230. 12 advantage = m[10]
  231. 12 dice_count_text = ""
  232. 12 dice_text = ""
  233. 12 dice_type1, dice_type2 = get_rolling_dice(attribute, skill, modifier)
  234. 12 then: 8 if dice_type1 <= dice_type2
  235. 8 then: 2 if advantage
  236. 2 then: 1 else: 1 if advantage == "A" && (dice_type1 > 4)
  237. 1 ability_dice_text, botch_dice = make_dice_a_roll(2, dice_type1)
  238. 1 @base_botch_dice += botch_dice # 能力ダメージ
  239. 1 dice_count_text = "(2D#{dice_type1})"
  240. 1 dice_text = ability_dice_text
  241. end
  242. else: 6 else
  243. 6 then: 6 else: 0 if dice_type1 > 4
  244. 6 ability_dice_text, botch_dice = make_dice_a_roll(1, dice_type1)
  245. 6 @base_botch_dice += botch_dice # 能力ダメージ
  246. 6 dice_count_text = "(1D#{dice_type1})"
  247. 6 dice_text = ability_dice_text
  248. end
  249. end
  250. 8 then: 8 else: 0 if dice_type2 > 4
  251. 8 skill_dice_text, botch_dice = make_dice_a_roll(1, dice_type2)
  252. 8 @skill_botch_dice += botch_dice
  253. 8 else: 1 then: 7 dice_count_text += "+" unless dice_count_text == ""
  254. 8 else: 1 then: 7 dice_text += "+" unless dice_text == ""
  255. 8 dice_count_text += "(1D#{dice_type2})"
  256. 8 dice_text += skill_dice_text
  257. end
  258. else: 4 else
  259. 4 then: 4 else: 0 if dice_type1 > 4
  260. 4 ability_dice_text, botch_dice = make_dice_a_roll(1, dice_type1)
  261. 4 @base_botch_dice += botch_dice # 能力ダメージ
  262. 4 dice_count_text = "(1D#{dice_type1})"
  263. 4 dice_text = ability_dice_text
  264. end
  265. 4 then: 2 if advantage
  266. 2 then: 1 else: 1 if advantage == "A" && (dice_type2 > 4)
  267. 1 skill_dice_text, botch_dice = make_dice_a_roll(2, dice_type2)
  268. 1 @skill_botch_dice += botch_dice
  269. 1 dice_count_text += "+(2D#{dice_type2})"
  270. 1 dice_text += "+#{skill_dice_text}"
  271. end
  272. else: 2 else
  273. 2 then: 0 else: 2 if dice_type2 > 4
  274. skill_dice_text, botch_dice = make_dice_a_roll(1, dice_type2)
  275. @skill_botch_dice += botch_dice
  276. dice_count_text += "+(1D#{dice_type2})"
  277. dice_text += "+#{skill_dice_text}"
  278. end
  279. end
  280. end
  281. 12 return make_result_with_myz(dice_count_text, dice_text)
  282. end
  283. end
  284. end
  285. end

lib/bcdice/game_system/Yggdrasill.rb

98.31% lines covered

91.03% branches covered

177 relevant lines. 174 lines covered and 3 lines missed.
78 total branches, 71 branches covered and 7 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/base"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class Yggdrasill < Base
  6. 1 ID = "Yggdrasill"
  7. 1 NAME = "鋼鉄のユグドラシル"
  8. 1 SORT_KEY = "こうてつのゆくとらしる"
  9. 1 HELP_MESSAGE = <<~HELP_MESSAGE
  10. ■ 行為判定 (CFx+nD6)
  11. クリティカルとファンブルによるダイス追加を行う
  12. 先頭のcfを変更することで、動作が変更される
  13. hcf: 達成値が半減
  14. cfl: 付加効果【幸運】を付与
  15. cfg: 付加効果【ギャンブル】を付与
  16. cft: 【応急処置】判定 (tは末尾に記入してください)
  17. 例)
  18. CF10+1D6, HCFL6+2D6, CFG11+1D6-2, cfgt10+1D6
  19. ■ 暴走ロール (RAx)
  20. 暴走率xの暴走ロールおよび臨界ロールを行う
  21. 例)
  22. RA50, RA110, RA150
  23. ■ SOペナルティ表 (SOx)
  24. スペック数がxオーバーした際のペナルティロールを行う
  25. 例)
  26. SO1, SO5
  27. ■ 【応急処置】 (TREATx)
  28. 達成値xの【応急処置】による回復量を決定する
  29. 例)
  30. TREAT1, TREAT18
  31. ■ その他の判定および表
  32. down:気絶判定
  33. cont:コンティニュー判定
  34. risk:リスク判定
  35. guki:偶奇判定
  36. cond:コンディションロール
  37. allr:オールレンジ発動ロール
  38. pafe:パーフェクト発動ロール
  39. stag:ステージ決定(電脳ロワイヤル用)
  40. fatal1:後遺症
  41. fatal2:因子変化ロール
  42. mikuzi:浅草寺みくじ。1d100であなたの運勢を占います
  43. HELP_MESSAGE
  44. 1 register_prefix(
  45. 'H?CF', 'RA', 'SO', 'DOWN', 'CO(NT)?',
  46. 'RISK', 'GUKI', 'COND', 'TREAT',
  47. 'ALLR', 'PAFE', 'FATAL', 'STAG', 'MIKUZI'
  48. )
  49. 1 def eval_game_system_specific_command(command)
  50. 182 roll_tables(command, TABLES) ||
  51. roll_cf(command) ||
  52. roll_ra(command) ||
  53. roll_treat(command) ||
  54. roll_down(command) ||
  55. roll_cond(command) ||
  56. roll_guki(command) ||
  57. roll_cont(command) ||
  58. roll_allr(command) ||
  59. roll_pafe(command)
  60. end
  61. 1 private
  62. 1 def roll_cf(command)
  63. # マイナス補正にダイスロールを用いることはシステム上ありえないため、正規表現ではじく
  64. 149 m = /^(H)?CF([LG])?(T)?((?:[+-]*\d+|\+?\d+D\d+)(?:[+-]+\d+|\++\d+D\d+)*)$/.match(command)
  65. 149 else: 80 then: 69 return nil unless m
  66. 80 hoge = !m[1].nil?
  67. 80 lucky_state = m[2]
  68. 80 treat_flg = !m[3].nil?
  69. 80 expr = m[4]
  70. 80 node = CommonCommand::AddDice::Parser.parse(expr)
  71. 80 else: 80 then: 0 return nil unless node
  72. 80 add_dice_randomizer = CommonCommand::AddDice::Randomizer.new(@randomizer, self)
  73. 80 total = node.lhs.eval(self, add_dice_randomizer)
  74. 80 rand_values = add_dice_randomizer.rand_results.map(&:value)
  75. 80 n1 = count_fumble(rand_values, lucky_state)
  76. 80 n_max = count_critical(rand_values, lucky_state)
  77. # ファンブルロール
  78. 80 fa_list = @randomizer.roll_barabara(n1, 6)
  79. 80 fa1 = fa_list.sum
  80. 80 fa2 = fa_list.join(",")
  81. 80 critical_rerolls = []
  82. 80 rerolls = n_max
  83. 80 body: 74 while rerolls > 0
  84. 74 list = @randomizer.roll_barabara(rerolls, 6)
  85. 74 critical_rerolls.push(list)
  86. 74 rerolls = list.count(6)
  87. end
  88. # crの達成値を合計する・cr出目を見易く
  89. 80 cr1 = critical_rerolls.flatten.sum
  90. 154 cr2 = critical_rerolls.map { |x| "[#{x.join(',')}]" }.join()
  91. # 修正値&一投目出目 -ファンブル +クリティカル
  92. 80 total_n = total - fa1 + cr1
  93. 80 then: 0 else: 80 total_n /= 2 if hoge == true
  94. # 最終達成値
  95. 80 result = "計【 #{total_n} 】"
  96. 80 text = "(#{command}) > #{result} : #{node.lhs.output}"
  97. # クリファン有無に応じて表示の追加
  98. 80 then: 40 else: 40 text += " (fa:#{n1})-#{fa1}[#{fa2}]" if n1 > 0
  99. 80 then: 47 else: 33 text += " (cr:#{n_max})+#{cr1}#{cr2} (cr:計#{critical_rerolls.flatten.size}回)" if cr1 > 0
  100. 80 else: 72 if treat_flg == true
  101. then: 8 # TREAT追加処理
  102. 8 heal = eval_game_system_specific_command("TREAT#{total_n}")
  103. 8 text += "\n > #{heal}"
  104. end
  105. 80 return text
  106. end
  107. 1 def count_critical(dice_list, lucky_state)
  108. threshold =
  109. 80 then: 17 if lucky_state == "G"
  110. 17 else: 63 4
  111. 63 then: 28 elsif lucky_state
  112. 28 5
  113. else: 35 else
  114. 35 6
  115. end
  116. 412 dice_list.count { |x| x >= threshold }
  117. end
  118. 1 def count_fumble(dice_list, lucky_state)
  119. threshold =
  120. 80 then: 17 if lucky_state == "G"
  121. 17 else: 63 3
  122. 63 then: 28 elsif lucky_state
  123. 28 2
  124. else: 35 else
  125. 35 1
  126. end
  127. 412 dice_list.count { |x| x <= threshold }
  128. end
  129. 1 def roll_ra(command)
  130. 69 m = /^RA(\d+)?$/.match(command)
  131. 69 else: 29 then: 40 return nil unless m
  132. body =
  133. 29 then: 29 else: 0 case m[1]&.to_i
  134. when: 6 when 50
  135. 6 RA50.roll(@randomizer)
  136. when: 8 when 70
  137. 8 RA70.roll(@randomizer)
  138. when: 12 when 90
  139. 12 RA90.roll(@randomizer)
  140. when: 2 when 110, 120, 130, 140
  141. 2 RA110.roll(@randomizer)
  142. when: 1 when 150
  143. 1 "> 因子崩壊【キャラロスト】"
  144. when: 0 when nil
  145. "> このコマンドは数値を付けてください"
  146. else: 0 else
  147. "> 指定の暴走率の暴走ロールはありません"
  148. end
  149. 29 "(#{command}) #{body}"
  150. end
  151. 1 def roll_treat(command)
  152. 40 m = /^TREAT(-?\d+)?$/.match(command)
  153. 40 else: 15 then: 25 return nil unless m
  154. 15 else: 14 then: 1 unless m[1]
  155. 1 return "AE【応急処置】 > このコマンドは数値を付けてください"
  156. end
  157. 14 then: 14 else: 0 value = m[1]&.to_i
  158. recovery =
  159. 14 then: 1 if value <= 5
  160. 1 else: 13 0
  161. 13 then: 1 elsif value <= 7
  162. 1 else: 12 1
  163. 12 then: 4 elsif value <= 11
  164. 4 dice = @randomizer.roll_once(6)
  165. 4 total = dice / 2
  166. 4 else: 8 "#{total}(#{dice}[#{dice}]/2)"
  167. 8 then: 2 elsif value <= 14
  168. 2 dice = @randomizer.roll_once(6)
  169. 2 else: 6 "#{dice}(#{dice}[#{dice}])"
  170. 6 then: 3 elsif value <= 17
  171. 3 dice = @randomizer.roll_once(6)
  172. 3 total = dice + 3
  173. 3 "#{total}(#{dice}[#{dice}]+3)"
  174. else: 3 else
  175. 3 list = @randomizer.roll_barabara(2, 6)
  176. 3 dice = list.sum()
  177. 3 total = dice + 2
  178. 3 "#{total}(#{dice}[#{list.join(',')}]+2)"
  179. end
  180. 14 "AE【応急処置】 > HPが#{recovery}回復"
  181. end
  182. 1 def roll_down(command)
  183. 25 else: 2 then: 23 return nil unless command == 'DOWN'
  184. 2 dice = @randomizer.roll_once(6)
  185. result =
  186. 2 then: 1 if dice.even?
  187. 1 "回避"
  188. else: 1 else
  189. 1 fell = @randomizer.roll_once(6)
  190. 1 "気絶【#{fell}R行動不能】"
  191. end
  192. 2 "気絶判定 > #{dice} > #{result}"
  193. end
  194. 1 def roll_cond(command)
  195. 23 else: 2 then: 21 return nil unless command == 'COND'
  196. 2 hp_list = @randomizer.roll_barabara(2, 6)
  197. 2 hp_total = hp_list.sum
  198. 2 hp_str = hp_list.join(",")
  199. 2 pp_list = @randomizer.roll_barabara(2, 6)
  200. 2 pp_total = pp_list.sum
  201. 2 pp_str = pp_list.join(",")
  202. 2 return "(#{command}) > HP#{hp_total}[#{hp_str}] 、 PP#{pp_total}[#{pp_str}]"
  203. end
  204. 1 def roll_guki(command)
  205. 21 else: 6 then: 15 return nil unless command == 'GUKI'
  206. 6 dice = @randomizer.roll_once(6)
  207. 6 then: 3 else: 3 result = dice.even? ? "成功" : "失敗"
  208. 6 "(GUKI) > #{dice} > #{result}"
  209. end
  210. 1 def roll_cont(command)
  211. 15 else: 2 then: 13 return nil unless /CO(NT)?/.match?(command)
  212. 2 dice = @randomizer.roll_once(6)
  213. 2 then: 1 else: 1 text = dice <= 4 ? "1R追加" : "2R追加"
  214. 2 "コンティニュー判定 > #{dice} > #{text}"
  215. end
  216. 1 def roll_allr(command)
  217. 13 else: 6 then: 7 return nil unless command == 'ALLR'
  218. 6 dice = @randomizer.roll_once(6)
  219. text =
  220. 6 then: 1 if dice == 1
  221. 1 "発動失敗【技対象が敵味方含めた全員となる】"
  222. else: 5 else
  223. 5 "発動成功"
  224. end
  225. 6 "オールレンジ判定 > #{dice} > #{text}"
  226. end
  227. 1 def roll_pafe(command)
  228. 7 else: 6 then: 1 return nil unless command == "PAFE"
  229. 6 dice = @randomizer.roll_once(6)
  230. text =
  231. 6 then: 1 if dice == 1
  232. 1 "発動失敗【通常命中・回避判定となり、発動時のアクション内の命中力&回避力が半減する】"
  233. else: 5 else
  234. 5 "発動成功"
  235. end
  236. 6 "発動ロール > #{dice} > #{text}"
  237. end
  238. 1 class YggTable < DiceTable::Table
  239. 1 def initialize(name, type, items, additonal_type:, additonal_format:, additonal_index:, out_of_control: nil)
  240. 7 super(name, type, items)
  241. 7 m = /(\d+)D(\d+)/i.match(additonal_type)
  242. 7 else: 7 then: 0 unless m
  243. raise ArgumentError, "Unexpected table type: #{additonal_type}"
  244. end
  245. 7 @additonal_times = m[1].to_i
  246. 7 @additonal_sides = m[2].to_i
  247. 7 @format = additonal_format
  248. 7 @index = additonal_index
  249. 7 @out_of_control = out_of_control
  250. end
  251. 1 def roll(randomizer)
  252. 28 value = randomizer.roll_sum(@times, @sides)
  253. 28 chosen = choice(value)
  254. 28 else: 11 then: 17 return chosen unless @index.include?(value) || @out_of_control == value
  255. body =
  256. 11 then: 3 if @out_of_control == value
  257. 3 "#{chosen.body} : #{RA90.roll(randomizer)}"
  258. else: 8 else
  259. 8 list = randomizer.roll_barabara(@additonal_times, @additonal_sides)
  260. 8 chosen.body + format(@format, total: list.sum(), list: list.join(","))
  261. end
  262. 11 DiceTable::RollResult.new(chosen.table_name, chosen.value, body)
  263. end
  264. end
  265. 1 class ChainTable < DiceTable::Table
  266. 1 def initialize(name, type, items, additonal_table:, additonal_index:)
  267. 1 super(name, type, items)
  268. 1 @additonal_table = additonal_table
  269. 1 @index = additonal_index
  270. end
  271. 1 def roll(randomizer)
  272. 5 value = randomizer.roll_sum(@times, @sides)
  273. 5 chosen = choice(value)
  274. 5 else: 3 then: 2 return chosen unless @index.include?(value)
  275. 3 body = "#{chosen.body} > #{@additonal_table.roll(randomizer)}"
  276. 3 DiceTable::RollResult.new(chosen.table_name, chosen.value, body)
  277. end
  278. end
  279. 1 PSY_TABLE = DiceTable::Table.new(
  280. "能力タイプ",
  281. "1D6",
  282. [
  283. 'サイキッカー',
  284. 'エスパー',
  285. 'トランサー',
  286. 'クリエイター',
  287. 'アンノウン',
  288. '好きな能力タイプを選択。ノーマル選択でも可'
  289. ]
  290. )
  291. 1 RA50 = YggTable.new(
  292. "暴走Lv.1",
  293. "1D6",
  294. [
  295. '発作【自爆÷2ダメージ。(自身に能力攻撃ロールダメージ÷2)。防御無視】',
  296. '高揚【1D6暴走率上昇】',
  297. '高揚【1D6暴走率上昇】',
  298. '自制【暴走なし】',
  299. '自制【暴走なし】',
  300. '自制【暴走なし】',
  301. ],
  302. additonal_type: "1D6",
  303. additonal_format: " : %{total}[%{list}] %",
  304. additonal_index: [2, 3]
  305. )
  306. 1 RA70 = YggTable.new(
  307. "暴走Lv.3",
  308. "1D6",
  309. [
  310. '自爆【自爆ダメージ。自身に能力攻撃ロールダメージ。防御無視】',
  311. '自爆【自爆ダメージ。自身に能力攻撃ロールダメージ。防御無視】',
  312. '暴発【ランダム攻撃。基本的に能力攻撃。対象は自分、キャラ、オブジェクトの三種類】',
  313. '連鎖【2D6暴走率上昇】',
  314. '発症',
  315. '自制【暴走無し】'
  316. ],
  317. additonal_type: "2D6",
  318. additonal_format: " : %{total}[%{list}] %",
  319. additonal_index: [4],
  320. out_of_control: 5
  321. )
  322. 1 RA90 = DiceTable::D66ParityTable.new(
  323. "暴走状態表",
  324. [
  325. '能力異常【能力使用時に偶奇判定。奇数の場合は消費だけ行い能力発動失敗。暴走チェックごとに+2%される(発症時も発生)。能力精度の判定結果が半減】',
  326. '言語異常【AE使用時に偶奇判定。奇数の場合は消費だけ行いAE発動失敗。話術の判定結果が半減】',
  327. '記憶異常【命中判定結果が半減する。知識の判定結果が半減】',
  328. '精神異常【自分のリアクション(回避判定など)で偶奇判定。奇数の場合は行動自動失敗。隠密、読心の判定結果が半減】',
  329. '忘我【自プリアクション時に偶奇判定。奇数の場合は宣言せずにターン終了。あらゆる技能判定結果が半減】',
  330. '自制【暴走無し】'
  331. ],
  332. [
  333. '制御異常【自プリアクション毎(行動決定前)に偶奇判定。奇数の場合は暴発によるランダム攻撃。(発症時も発生)。技術、幸運の判定結果が半減】',
  334. '過負荷【ワンアクション毎に能力精度÷3の防御無視ダメージ(発症時も発生)。閃きの判定結果が半減】',
  335. '聴覚異常【回避判定結果が半減する。察知の半減結果が半減】',
  336. '視覚異常【SS&命中力&回避力が半減する※判定結果は半減しない。観察眼の判定結果が半減】',
  337. '身体異常【防御を差し引く前のダメージロールが半減する。力技、俊敏の判定結果が半減】',
  338. '自制【暴走なし】'
  339. ]
  340. )
  341. 1 RA110 = YggTable.new(
  342. "臨界ロール",
  343. "1D6",
  344. [
  345. '自壊【自爆ダメージ。自身の最も高い攻撃ロールダメージ。防御無視】',
  346. '超活性【HP・PPを2D6回復】',
  347. '自壊【自爆ダメージ。自身の最も高い攻撃ロールダメージ。防御無視】',
  348. '超活性【HP・PPを2D6回復】',
  349. '自壊【自爆ダメージ。自身の最も高い攻撃ロールダメージ。防御無視】',
  350. '超活性【HP・PPを2D6回復】'
  351. ],
  352. additonal_type: "2D6",
  353. additonal_format: " : %{total}[%{list}] 回復",
  354. additonal_index: [2, 4, 6]
  355. )
  356. TABLES = {
  357. 1 "MIKUZI" => DiceTable::RangeTable.new(
  358. "おみくじ",
  359. "1D100",
  360. [
  361. [1..17, "大吉"],
  362. [18..52, "吉"],
  363. [53..57, "半吉"],
  364. [58..61, "小吉"],
  365. [62..64, "末小吉"],
  366. [65..70, "末吉"],
  367. [71..100, "凶"],
  368. ]
  369. ),
  370. "SO1" => YggTable.new(
  371. "SOペナルティ表 1オーバー",
  372. "1D6",
  373. [
  374. '消費負荷【PP2倍消費 ※AE消費は含まない】',
  375. '消費負荷【PP2倍消費 ※AE消費は含まない】',
  376. '消費負荷【PP2倍消費 ※AE消費は含まない】',
  377. '反動',
  378. '反動',
  379. '制御成功【発動成功 ペナルティ無し】'
  380. ],
  381. additonal_type: "1D6",
  382. additonal_format: "【命中&回避-1D6(%{total}[%{list}]) 1ラウンド継続】",
  383. additonal_index: [4, 5]
  384. ),
  385. "SO2" => YggTable.new(
  386. "SOペナルティ表 2オーバー",
  387. "1D6",
  388. [
  389. '自爆【自分へ能力攻撃ダメージ ※防御無視】',
  390. '消費負荷【PP2倍消費 ※AE消費は含まない】',
  391. '消費負荷【PP2倍消費 ※AE消費は含まない】',
  392. '反動',
  393. '反動',
  394. '制御成功【発動成功 ペナルティ無し】'
  395. ],
  396. additonal_type: "1D6",
  397. additonal_format: "【命中&回避-1D6(%{total}[%{list}]) 1ラウンド継続】",
  398. additonal_index: [4, 5]
  399. ),
  400. "SO3" => YggTable.new(
  401. "SOペナルティ表 3オーバー",
  402. "1D6",
  403. [
  404. '自爆【自分へ能力攻撃ダメージ ※防御無視】',
  405. '自爆【自分へ能力攻撃ダメージ ※防御無視】',
  406. '消費負荷【PP2倍消費 ※AE消費は含まない】',
  407. '過反動',
  408. '過反動',
  409. '制御成功【発動成功 ペナルティ無し】'
  410. ],
  411. additonal_type: "2D6",
  412. additonal_format: "【命中&回避-2D6(%{total}[%{list}]) 1ラウンド継続】",
  413. additonal_index: [4, 5]
  414. ),
  415. "SO4" => YggTable.new(
  416. "SOペナルティ表 4オーバー",
  417. "1D6",
  418. [
  419. '崩壊【自爆ダメージ×2 ※防御無視】',
  420. '崩壊【自爆ダメージ×2 ※防御無視】',
  421. '超負荷【PP3倍消費 ※AE消費は含まない】',
  422. '過反動',
  423. '過反動',
  424. '制御成功【発動成功 ペナルティ無し】',
  425. ],
  426. additonal_type: "2D6",
  427. additonal_format: "【命中&回避-2D6(%{total}[%{list}]) 1ラウンド継続】",
  428. additonal_index: [4, 5]
  429. ),
  430. "SO5" => DiceTable::Table.new(
  431. "SOペナルティ表 5オーバー",
  432. "1D6",
  433. [
  434. '崩壊【自爆ダメージ×2 ※防御無視】',
  435. '崩壊【自爆ダメージ×2 ※防御無視】',
  436. '崩壊【自爆ダメージ×2 ※防御無視】',
  437. '超負荷【PP3倍消費 ※AE消費は含まない】',
  438. '超負荷【PP3倍消費 ※AE消費は含まない】',
  439. '制御成功【発動成功 ペナルティ無し】'
  440. ]
  441. ),
  442. "RISK" => DiceTable::Table.new(
  443. "リスク判定",
  444. "1D6",
  445. [
  446. '能力自爆【能力は発動せず、PPを2倍消費する。併用AEのPPは含まない。それに加え【自爆】する。能力攻撃力分を自身へ防御無視ダメージ】',
  447. '能力不発【能力は発動せず、PPを2倍消費する。併用AEのPPは含まない】',
  448. '効果不発【リスクの効果はゼロで能力発動】',
  449. '通常発動【(能力精度÷3)+1D6を加える】',
  450. '活性発動【(能力精度÷3)+2D6を加える】',
  451. '覚醒発動【(能力精度÷3)+3D6を加える】'
  452. ]
  453. ),
  454. "FATAL1" => DiceTable::Table.new(
  455. "後遺症判定",
  456. "1D6",
  457. [
  458. '聴覚崩壊【聴覚に異常が起きる。幻聴、難聴、失聴、など】',
  459. '視覚崩壊【視覚に異常が起こる。幻覚、色盲、失明、など】',
  460. '言語崩壊【言語の認識に異常が起きる。しゃべる事に支障をきたす。吃音、失語症、失読症、など】',
  461. '身体崩壊【身体に異常が起こる。欠損、異形化、麻痺、など】',
  462. '精神崩壊【精神に異常が起こる。人格破綻、性格変化、妄想・幻覚による異常行動、など】',
  463. '記憶崩壊【記憶に異常が起こる。記憶障害、記憶喪失、など】'
  464. ]
  465. ),
  466. "FATAL2" => ChainTable.new(
  467. "因子変化判定",
  468. "1D6",
  469. [
  470. '能力変化【能力がまったく別ものに変化する】',
  471. '能力変化【能力がまったく別ものに変化する】',
  472. '因子抑制【能力変化は起こらない】',
  473. '因子抑制【能力変化は起こらない】',
  474. '能力喪失・能力覚醒【能力を持つものは失い、ノーマルは能力に覚醒する。喪失者はノーマルのキャラ特性ポイントを1p獲得する。覚醒者はノーマルのキャラ特性ポイントを1p失い、キャラ特性を6つ取得していた場合は1つ喪失する】',
  475. '能力喪失・能力覚醒【能力を持つものは失い、ノーマルは能力に覚醒する。喪失者はノーマルのキャラ特性ポイントを1p獲得する。覚醒者はノーマルのキャラ特性ポイントを1p失い、キャラ特性を6つ取得していた場合は1つ喪失する】',
  476. ],
  477. additonal_table: PSY_TABLE,
  478. additonal_index: [1, 2, 5, 6]
  479. ),
  480. "STAG" => DiceTable::D66Table.new(
  481. "ステージ決定",
  482. D66SortType::NO_SORT,
  483. {
  484. 11 => 'ロシアンルーレット【幸運にて判定。参加者は銃をこめかみにあて、1発の銃弾をひかないように祈る。 敗者は3D6ダメージ】',
  485. 12 => 'チキンレース【察知にて判定。に向ってバイクでダッシュだ。敗者は2D6ダメージ。落ちても大丈夫です、電脳だから】',
  486. 13 => '取り立て【力技or威圧にて判定。あのモヒカン借金払わないんですよ。よろしくお願いしますね。電脳を通しての実際の取り立てらしい】',
  487. 14 => '舌戦【威圧or話術にて判定。参加者同士で舌戦で勝者を決めろ!敗者は心に2D6ダメージ】',
  488. 15 => 'ギャンブル【読心or幸運にて判定。ポーカー、ルーレット、麻雀、好きなものを選べ。勝利の鍵は運か、それとも人の心か】',
  489. 16 => 'トラップ【SSにて判定。君達の目の前に広がるのはそう、地雷原だ。敗者は3D6ダメージ】',
  490. 21 => 'サバゲー【隠密or俊敏にて判定。軍人となって、相手を屠れ!敗者は死ぬ。敗者は2D6ダメージ】',
  491. 22 => '追跡【察知or隠密にて判定。ニンジャの姿となって下手人を追え!コアな人気を誇るステージ。ニンジャ人気すごい】',
  492. 23 => '推理【閃きにて判定。あなたたちは探偵となり、事件を解決に導く。犯人は、お前だ!2時間放送になるのが玉に瑕】',
  493. 24 => '潜入【隠密にて判定。スパイとなり、機密情報を盗め!あれ、これ実際の企業の機密情報じゃ・・・?】',
  494. 25 => 'かくれんぼ【隠密or読心にて判定。あなたを追うのはホラーな化け物・・・。スリリングなかくれんぼをどうぞ堪能下さい】',
  495. 26 => '絶対絶命!【回避力にて判定。君達はマフィアにおびき出されたのだ。大勢の銃が君を狙う。敗者は3D6ダメージ】',
  496. 31 => 'クイズ【知識にて判定。己の知識を存分に披露しろ!負けたら奈落に落されます。敗者は1D6ダメージ】',
  497. 32 => '迷路【察知or幸運にて判定。巨大迷路をクリアしろ!あれ、なんでこんなところに骸骨が・・・】',
  498. 33 => 'パズル【知識or閃きにて判定。3Dの難解パズルを解き明かせ!!時折金庫破りのパスワードがターゲットになってたり】',
  499. 34 => '間違い探し【観察眼or閃きにて判定。大量の鍵から正しい鍵を。美女の中からオカマを。そんな間違いを見つけるのだ!】',
  500. 35 => '目利き【観察眼or知識にて判定。あなたの鑑定で値段を当てろ!はずれたらかっこ悪いです】',
  501. 36 => 'スナイパー【命中力にて判定。一撃必殺でターゲットを仕留めろ!なお、ターゲットはお互いだ。敗者は2D6ダメージ】',
  502. 41 => '腕相撲【力技にて判定。必要なのは、力のみ!!敗者は2D6ダメージ】',
  503. 42 => 'インディジョーンズ【俊敏にて判定。なぜか大岩が後ろから!逃げろー!敗者は3D6ダメージ】',
  504. 43 => 'PK【力技or察知にて判定。見極め、ゴールしろ!パワーで破ってもいい】',
  505. 44 => 'ダンス【技術or俊敏にて判定。己の舞を魅せろ!ジャンル問わず】',
  506. 45 => 'ボディコンテスト【威圧にて判定。魅せるのはマッスルか、それとも美しい肢体か!容姿ボーナスはつきません】',
  507. 46 => '突破しろ!【ダメージ量にて判定。立ちはだかる扉をぶち破れ!扉は防御10】',
  508. 51 => '早食い【力技or俊敏にて判定。くって!くって!!くいまくれ!!敗者は胃に2D6ダメージ】',
  509. 52 => 'ナンパ天国【話術or読心にて判定。電脳世界で老若男女を口説き落せ!相手はプログラムだったり電脳に入っているアバターだったり】',
  510. 53 => 'スリーサイズ【観察眼にて判定。魅惑のボディをなめまわせ!勝利者はある意味で尊敬され、ある意味で嫌われる】',
  511. 54 => 'ワサビ寿司【観察眼or幸運にて判定。高級寿司の中に、死ぬほどの刺激が・・・!敗者は2D6ダメージ】',
  512. 55 => 'じゃんけん【読心にて判定。じゃんけんとは運ではない、読み合いなのだ!】',
  513. 56 => '瓦割り【ダメージ量にて判定。どんな方法でもいい。とにかく枚数を割れ!!!ダメージ量の2倍くらいが割った枚数】',
  514. 61 => '料理対決【知識or技術にて判定。胃袋をつかめ!絶品料理対決!料理によってはR18G指定になる場合がある】',
  515. 62 => '歌合戦【威圧or技術にて判定。その歌唱力で心をつかめ!アイドルデビューも夢じゃない!電脳なのでお好きな衣装でどうぞ】',
  516. 63 => '漫才【話術or閃きにて判定。即興漫才で画面の向こうを爆笑の渦へ!相方が必要な方は漫才プログラムアバターをレンタル。有料】',
  517. 64 => '画伯【技術にて判定。テーマをもとに、あなたの画力を見せつけろ!時々下手うまな人が勝つことも】',
  518. 65 => 'プレゼンテーション【話術にて判定。本日の商品は、こちら!!実際に販売します。してもらいます】',
  519. 66 => '無双撃破!【ダメージ量にて判定。た、大量のモヒカンだぁ~!ダメージ量の2倍くらいが倒した数。敗者は2D6ダメージ。SE【オールレンジ】技は成功で判定+10】'
  520. }
  521. )
  522. }.freeze
  523. end
  524. end
  525. end

lib/bcdice/game_system/Yotabana.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Yotabana < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "Yotabana"
  7. # ゲームシステム名
  8. 1 NAME = "ヨタバナ"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "よたはな"
  11. # ダイスボットの使い方
  12. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  13. ▪️ 各種表
  14. COT 収束表
  15. EVT イベント表
  16. INFO_MESSAGE_TEXT
  17. 1 def eval_game_system_specific_command(command)
  18. 2 roll_tables(command, TABLES)
  19. end
  20. TABLES = {
  21. 1 "COT" => DiceTable::Table.new(
  22. "収束表",
  23. "1D6",
  24. [
  25. "サプライズ忍者/唐突に忍者が乱入し、場面にいるキャラクターを倒して去っていく",
  26. "仙人/唐突に仙人が乱入し、不思議な力で事態を収束させて帰っていく",
  27. "洗脳薬/不思議な薬が散布され、キャラクターを洗脳し、事態を収束させる",
  28. "作者の手/キャラクターたちの言動が唐突に変わり、事態が収束する。作者の大いなる手だ……",
  29. "神の奇跡/神が奇跡を起こし事態を収束させる。または神の信徒になり、信仰の前に争いは無意味であると悟る",
  30. "和解/話し合えば分かり合えた。この世は対話で通じ合える",
  31. ]
  32. ),
  33. "EVT" => DiceTable::Table.new(
  34. "イベント表",
  35. "1D12",
  36. [
  37. "道端に刺さっていた聖剣を拾う",
  38. "ゾンビの群れと遭遇する",
  39. "落ちていたコインを拾う。ちょっとラッキーな気分になる",
  40. "あらゆるところで爆発が!?",
  41. "唐突に冬が訪れ、猛吹雪が襲う",
  42. "無人のトラックが突っ込んでくる",
  43. "ネコちゃんに懐かれる",
  44. "料金滞納で水道を止められる",
  45. "ゴキゲンな音楽が鳴り響く",
  46. "水着になる",
  47. "オークションにかけられる",
  48. "殺人アンドロイドが襲いかかってくる",
  49. ]
  50. ),
  51. }.freeze
  52. 1 register_prefix(TABLES.keys)
  53. end
  54. end
  55. end

lib/bcdice/game_system/YuMyoKishi.rb

100.0% lines covered

100.0% branches covered

46 relevant lines. 46 lines covered and 0 lines missed.
24 total branches, 24 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/base'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class YuMyoKishi < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'YuMyoKishi'
  8. # ゲームシステム名
  9. 1 NAME = '幽冥鬼使'
  10. # ゲームシステム名の読みがな
  11. #
  12. # 「ゲームシステム名の読みがなの設定方法」(docs/dicebot_sort_key.md)を参考にして
  13. # 設定してください
  14. 1 SORT_KEY = 'ゆうみようきし'
  15. # ダイスボットの使い方
  16. 1 HELP_MESSAGE = <<~MESSAGETEXT
  17. ■判定 YM+a>=b a:技能値(省略可) b:目標値(省略可)
  18.  例:YM+4>=8: 技能値による修正が+4で、目標値8の克服判定を行う
  19.    YM>=8 : 技能値による修正なしで、目標値8の克服判定を行う
  20.    YM+6 : 技能値による修正が+6で、達成値を確認する
  21. ■代償表 COT
  22. ■転禍表 TRT
  23. MESSAGETEXT
  24. TABLES = {
  25. 1 "COT" => DiceTable::Table.new(
  26. "代償表",
  27. "2D6",
  28. [
  29. "不慮の出逢い",
  30. "深淵を覗くとき",
  31. "時間の消費",
  32. "奇妙な情報",
  33. "優柔不断",
  34. "注意散漫",
  35. "心身耗弱",
  36. "不穏な情報",
  37. "遺留品",
  38. "迫りくる危機",
  39. "正体の露見",
  40. ]
  41. ),
  42. "TRT" => DiceTable::Table.new(
  43. "転禍表",
  44. "2D6",
  45. [
  46. "○○と瓜二つ",
  47. "絶対絶命",
  48. "悪癖災う",
  49. "冷酷な指令",
  50. "おびえる視線",
  51. "絡みつく妖気",
  52. "容赦ない評定",
  53. "無力な市民",
  54. "未練阻む",
  55. "縁の枷",
  56. "邪悪な刻印",
  57. ]
  58. ),
  59. }.freeze
  60. # ダイスボットで使用するコマンドを配列で列挙する
  61. 1 register_prefix("YM", TABLES.keys)
  62. 1 def eval_game_system_specific_command(command)
  63. 28 debug("eval_game_system_specific_command Begin")
  64. 28 return roll_command(command) || roll_tables(command, TABLES)
  65. end
  66. 1 def roll_command(command)
  67. 28 parser = Command::Parser.new('YM', round_type: round_type)
  68. .restrict_cmp_op_to(:>=, nil)
  69. 28 cmd = parser.parse(command)
  70. 28 else: 24 then: 4 unless cmd
  71. 4 return nil
  72. end
  73. 24 dice_list = @randomizer.roll_barabara(4, 6)
  74. 24 value, status = sip_pat_a(dice_list)
  75. 24 then: 2 else: 22 achievement = status == :wumian ? 0 : value + cmd.modify_number
  76. roll_text = [
  77. 24 cmd.to_s,
  78. dice_list.join(','),
  79. value,
  80. 24 then: 6 else: 18 value == achievement ? nil : achievement,
  81. ].compact.join(" > ")
  82. 24 then: 15 if cmd.target_number.nil?
  83. 15 then: 1 if status == :wumian
  84. 1 else: 14 Result.failure(roll_text)
  85. 14 then: 2 elsif status == :yise
  86. 2 Result.critical(roll_text)
  87. else: 12 else
  88. 12 Result.new(roll_text)
  89. else: 9 end
  90. 9 then: 1 elsif status == :wumian
  91. 1 else: 8 Result.failure([roll_text, "可"].join(" > "))
  92. 8 then: 2 elsif status == :yise
  93. 2 else: 6 Result.critical([roll_text, "優"].join(" > "))
  94. 6 then: 3 elsif achievement >= cmd.target_number
  95. 3 Result.success([roll_text, "良"].join(" > "))
  96. else: 3 else
  97. 3 Result.failure([roll_text, "可"].join(" > "))
  98. end
  99. end
  100. 1 def sip_pat_a(dice_list) # 十八仔
  101. 24 result = dice_list.each_with_object(Hash.new(0)) do |cur, acc|
  102. 96 acc[cur] += 1
  103. end
  104. 24 case result.count
  105. when 1
  106. when: 4 # 全てゾロ目
  107. 4 [20, :yise] # 一色
  108. when: 10 when 2
  109. 10 if result.values == [2, 2]
  110. then: 4 # 同値のダイスが2つずつ
  111. 4 [result.keys.max * 2, :normal]
  112. else
  113. else: 6 # 3つの同値と1つの目のダイス
  114. 6 [result.keys.sum, :normal]
  115. end
  116. when 3
  117. when: 8 # 2つの同値と1つずつの目のダイス
  118. 32 [result.select { |_k, v| v == 1 }.keys.sum, :normal]
  119. else
  120. else: 2 # 全部バラバラ
  121. 2 [0, :wumian] # 無面
  122. end
  123. end
  124. end
  125. end
  126. end

lib/bcdice/game_system/ZettaiReido.rb

100.0% lines covered

95.45% branches covered

69 relevant lines. 69 lines covered and 0 lines missed.
22 total branches, 21 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require 'bcdice/base'
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class ZettaiReido < Base
  6. # ゲームシステムの識別子
  7. 1 ID = 'ZettaiReido'
  8. # ゲームシステム名
  9. 1 NAME = '絶対隷奴'
  10. # ゲームシステム名の読みがな
  11. 1 SORT_KEY = 'せつたいれいと'
  12. # ダイスボットの使い方
  13. 1 HELP_MESSAGE = <<~INFO_MESSAGE_TEXT
  14. ・判定
  15. m-2DR+n>=x
  16. m(基本能力),n(修正値),x(目標値)
  17. DPの取得の有無も表示されます。
  18. INFO_MESSAGE_TEXT
  19. 1 register_prefix('\d+\-2DR')
  20. 1 def eval_game_system_specific_command(command)
  21. 15 else: 15 then: 0 return nil unless command =~ /^(\d+)-2DR([+\-\d]*)(>=(\d+))?$/i
  22. 15 baseAvility = Regexp.last_match(1).to_i
  23. 15 modText = Regexp.last_match(2)
  24. 15 diffValue = Regexp.last_match(4)
  25. 15 return roll2DR(baseAvility, modText, diffValue)
  26. end
  27. 1 def roll2DR(baseAvility, modText, diffValue)
  28. 15 diceTotal, diceText, darkPoint = roll2DarkDice()
  29. 15 mod, modText = getModInfo(modText)
  30. 15 diff, diffText = getDiffInfo(diffValue)
  31. 15 baseCommandText = "(#{baseAvility}-2DR#{modText}#{diffText})"
  32. 15 diceCommandText = "#{baseAvility}-#{diceTotal}[#{diceText}]#{modText}"
  33. 15 total = baseAvility - diceTotal + mod
  34. 15 result = getResult(diceTotal, total, diff)
  35. 15 then: 6 else: 9 darkPointText = "#{darkPoint}DP" if darkPoint > 0
  36. 15 result.text = [
  37. baseCommandText,
  38. diceCommandText,
  39. total.to_i,
  40. result.text,
  41. darkPointText,
  42. ].compact.join(" > ")
  43. 15 return result
  44. end
  45. 1 def roll2DarkDice()
  46. 15 dice1 = @randomizer.roll_once(6)
  47. 15 dice2 = @randomizer.roll_once(6)
  48. 15 darkDice1, darkPoint1 = changeDiceToDarkDice(dice1)
  49. 15 darkDice2, darkPoint2 = changeDiceToDarkDice(dice2)
  50. 15 darkPoint = darkPoint1 + darkPoint2
  51. 15 then: 3 else: 12 if darkPoint == 2
  52. 3 darkPoint = 4
  53. end
  54. 15 darkTotal = darkDice1 + darkDice2
  55. 15 darkDiceText = "#{darkDice1},#{darkDice2}"
  56. 15 return darkTotal, darkDiceText, darkPoint
  57. end
  58. 1 def changeDiceToDarkDice(dice)
  59. 30 darkPoint = 0
  60. 30 darkDice = dice
  61. 30 then: 9 else: 21 if dice == 6
  62. 9 darkDice = 0
  63. 9 darkPoint = 1
  64. end
  65. 30 return darkDice, darkPoint
  66. end
  67. 1 def getModInfo(modText)
  68. 15 value = ArithmeticEvaluator.eval(modText)
  69. 15 text = ""
  70. 15 then: 4 if value < 0
  71. 4 else: 11 text = value.to_s
  72. 11 then: 2 else: 9 elsif value > 0
  73. 2 text = "+" + value.to_s
  74. end
  75. 15 return value, text
  76. end
  77. 1 def getDiffInfo(diffValue)
  78. 15 diffText = ""
  79. 15 else: 5 then: 10 unless diffValue.nil?
  80. 10 diffValue = diffValue.to_i
  81. 10 diffText = ">=#{diffValue.to_i}"
  82. end
  83. 15 return diffValue, diffText
  84. end
  85. 1 def getResult(diceTotal, total, diff)
  86. 15 then: 3 else: 12 if diceTotal == 0
  87. 3 return Result.critical("クリティカル")
  88. end
  89. 12 then: 3 else: 9 if diceTotal == 10
  90. 3 return Result.fumble("ファンブル")
  91. end
  92. 9 then: 3 else: 6 if diff.nil?
  93. 3 diff = 0
  94. end
  95. 9 successLevel = (total - diff)
  96. 9 then: 6 else: 3 if successLevel >= 0
  97. 6 return Result.success("#{successLevel} 成功")
  98. end
  99. 3 return Result.failure("失敗")
  100. end
  101. end
  102. end
  103. end

lib/bcdice/game_system/ZombiLine.rb

100.0% lines covered

100.0% branches covered

44 relevant lines. 44 lines covered and 0 lines missed.
12 total branches, 12 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class ZombiLine < Base
  5. # ゲームシステムの識別子
  6. 1 ID = "ZombiLine"
  7. # ゲームシステム名
  8. 1 NAME = "ゾンビライン"
  9. # ゲームシステム名の読みがな
  10. 1 SORT_KEY = "そんひらいん"
  11. 1 HELP_MESSAGE = <<~TEXT
  12. ■ 判定 (xZL<=y)
  13.  x:ダイス数(省略時は1)
  14.  y:成功率
  15. ■ 各種表
  16.  ストレス症状表 SST
  17.  食材表 IT
  18. TEXT
  19. 1 def initialize(command)
  20. 23 super(command)
  21. 23 @sides_implicit_d = 10
  22. end
  23. 1 def eval_game_system_specific_command(command)
  24. 23 return check_action(command) || roll_tables(command, TABLES)
  25. end
  26. 1 def check_action(command)
  27. 23 parser = Command::Parser.new("ZL", round_type: @round_type)
  28. .enable_prefix_number
  29. .disable_modifier
  30. .restrict_cmp_op_to(:<=)
  31. 23 parsed = parser.parse(command)
  32. 23 else: 16 then: 7 unless parsed
  33. 7 return nil
  34. end
  35. 16 dice_count = parsed.prefix_number || 1
  36. 16 target_num = parsed.target_number
  37. 16 debug(dice_count)
  38. 16 dice_list = @randomizer.roll_barabara(dice_count, 100).sort
  39. 33 is_success = dice_list.any? { |i| i <= target_num }
  40. 36 is_critical = dice_list.any? { |i| i <= 5 }
  41. 38 is_fumble = dice_list.any? { |i| i >= 96 && i > target_num }
  42. 16 then: 1 else: 15 if is_critical && is_fumble
  43. 1 is_critical = false
  44. 1 is_fumble = false
  45. end
  46. success_message =
  47. 16 then: 2 if is_success && is_critical
  48. 2 else: 14 "成功(クリティカル)"
  49. 14 then: 1 elsif is_success && is_fumble
  50. 1 else: 13 "成功(ファンブル)"
  51. 13 then: 8 elsif is_success
  52. 8 else: 5 "成功"
  53. 5 then: 2 elsif is_fumble
  54. 2 "失敗(ファンブル)"
  55. else: 3 else
  56. 3 "失敗"
  57. end
  58. sequence = [
  59. 16 "(#{parsed})",
  60. "[#{dice_list.join(',')}]",
  61. success_message
  62. ]
  63. 16 Result.new.tap do |r|
  64. 16 r.text = sequence.join(" > ")
  65. 16 r.condition = is_success
  66. 16 r.critical = is_critical
  67. 16 r.fumble = is_fumble
  68. end
  69. end
  70. TABLES = {
  71. 1 'SST' => DiceTable::Table.new(
  72. 'ストレス症状表',
  73. '1D10',
  74. [
  75. '憤怒:一番近い敵を攻撃(成功率+20%)しにいきます。近くに敵がいない場合、誰かのストレスを+1させます。 頭に血が上り、誰かに怒りをぶつけます。',
  76. '逃避:落下してでも敵から逃げるように移動します。周囲に敵が居ない場合、現実逃避します。 耐えられなくなり、逃げ出します。',
  77. '幻覚:戦闘中は、「行動放棄(全AP)」します。戦闘以外なら、幻覚を見て笑います。 自分が望む幻覚が見えます。',
  78. '絶叫:戦闘中は、「注目を集める(2AP)」をします。戦闘以外なら、無意味に叫びます。 思わず叫んでしまいます。',
  79. '自傷:自ら【怪我】を負います。戦闘中は「自傷行為(1AP)」をして自分が【怪我】します。 思わず自分を傷つけます。',
  80. '不安:誰かのストレスを1上げます。近くに誰も居ない場合、泣き出します。 不安にかられて余計なことを言います。',
  81. '忌避:その場から一番近い対象に「石(1AP)」を投げます。それができない場合、【転倒】してうずくまります。 嫌悪感から全てを拒みます。',
  82. '暴走:一番近い敵を攻撃しにいきます。近くに敵がいない場合、周りの意見も聞かずに安直な行動をします。 冷静でいられなくなり、直情的になります。',
  83. '混乱:近くにいるランダムな対象に格闘で攻撃しにいきます。それができない場合、「行動放棄(全 AP)」します。 世界全てが敵に見えて攻撃します。',
  84. '開眼:ストレスは0まで下がります。あなたは教祖となって教義をひとつつくって「布教」できます。次の症状が出るまで効果は続きます。 ゾンビだらけの世界の真理を見つけます。',
  85. ]
  86. ),
  87. 'IT' => DiceTable::RangeTable.new(
  88. '食材表',
  89. '1d100',
  90. [
  91. [1..50, '生モノ食材'],
  92. [51..80, '怪しい食材'],
  93. [81..100, '危ない食材']
  94. ]
  95. )
  96. }.freeze
  97. 1 register_prefix('\d*ZL', TABLES.keys)
  98. end
  99. end
  100. end

lib/bcdice/game_system/beginning_idol/accessories_table.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BeginningIdol < Base
  5. 1 class << self
  6. 1 private
  7. # @params locale [Symbol]
  8. # @return [ChainTable]
  9. 1 def translate_accessories_table(locale)
  10. 2 items = I18n.t("BeginningIdol.ACT.items", locale: locale)
  11. subtables = [
  12. 2 DiceTable::D66Table.from_i18n("BeginningIdol.ACT.subtables.head", locale),
  13. DiceTable::D66Table.from_i18n("BeginningIdol.ACT.subtables.hat", locale),
  14. DiceTable::D66Table.from_i18n("BeginningIdol.ACT.subtables.body", locale),
  15. DiceTable::D66Table.from_i18n("BeginningIdol.ACT.subtables.arm", locale),
  16. DiceTable::D66Table.from_i18n("BeginningIdol.ACT.subtables.foot", locale),
  17. DiceTable::D66Table.from_i18n("BeginningIdol.ACT.subtables.other", locale),
  18. ]
  19. 2 ChainTable.new(
  20. I18n.t("BeginningIdol.ACT.name", locale: locale),
  21. "1D6",
  22. items.zip(subtables)
  23. )
  24. end
  25. end
  26. end
  27. end
  28. end

lib/bcdice/game_system/beginning_idol/bad_status_table.rb

100.0% lines covered

100.0% branches covered

23 relevant lines. 23 lines covered and 0 lines missed.
8 total branches, 8 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BeginningIdol < Base
  5. 1 class BadStatusTable
  6. 1 def initialize(locale)
  7. 4 @locale = locale
  8. end
  9. 1 def roll_command(randomizer, command)
  10. 295 m = /^BT(\d+)?$/.match(command)
  11. 295 else: 8 then: 287 unless m
  12. 287 return nil
  13. end
  14. 8 then: 6 else: 2 roll_counts = m[1]&.to_i || 1
  15. 8 return roll(randomizer, roll_counts)
  16. end
  17. # @param randomizer [BCDice::Randomizer]
  18. # @param counts [Integer]
  19. 1 def roll(randomizer, roll_counts = 1)
  20. 17 then: 2 else: 15 if roll_counts <= 0
  21. 2 return nil
  22. end
  23. 15 name = I18n.t("BeginningIdol.BT.name", locale: @locale)
  24. 15 items = I18n.t("BeginningIdol.BT.items", locale: @locale)
  25. 15 prefix_format = I18n.t("BeginningIdol.BT.prefix_format", locale: @locale)
  26. 15 dice_list = randomizer.roll_barabara(roll_counts, 6).sort
  27. 15 index_list = dice_list.uniq
  28. 15 then: 6 else: 9 result_prefix = format(prefix_format, count_bad_status: index_list.size) + "\n" if index_list.size > 1
  29. 40 result_text = index_list.map { |i| items[i - 1] }.join("\n")
  30. 15 return "#{name} > [#{dice_list.join(',')}] > #{result_prefix}#{result_text}"
  31. end
  32. end
  33. end
  34. end
  35. end

lib/bcdice/game_system/beginning_idol/chain_d66_table.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BeginningIdol < Base
  5. 1 class ChainD66Table
  6. # @param [String] name 表の名前
  7. # @param [Array<Array<String, #roll>>] items 表の項目の配列
  8. 1 def initialize(name, items)
  9. 4 @name = name
  10. 4 @items = items.freeze
  11. end
  12. # 表を振る
  13. # @param randomizer [#roll_sum] ランダマイザ
  14. # @return [String] 結果
  15. 1 def roll(randomizer)
  16. 6 dice = randomizer.roll_barabara(2, 6).sort
  17. 6 value = dice[0] * 10 + dice[1]
  18. 6 chosen = @items[value]
  19. 18 then: 6 else: 6 body = chosen.map { |item| item.respond_to?(:roll) ? item.roll(randomizer) : item }.join("\n")
  20. 6 return "#{@name}(#{value}) > #{body}"
  21. end
  22. end
  23. end
  24. end
  25. end

lib/bcdice/game_system/beginning_idol/chain_table.rb

94.44% lines covered

75.0% branches covered

18 relevant lines. 17 lines covered and 1 lines missed.
4 total branches, 3 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BeginningIdol < Base
  5. 1 class ChainTable
  6. # @param [String] name 表の名前
  7. # @param [String] type 項目を選ぶときのダイスロールの方法 '1D6'など
  8. # @param [Array<Array<String, #roll>>] items 表の項目の配列
  9. 1 def initialize(name, type, items)
  10. 8 @name = name
  11. 8 @items = items.freeze
  12. 8 m = /^(\d+)D(\d+)$/i.match(type)
  13. 8 else: 8 then: 0 unless m
  14. raise ArgumentError, "Unexpected table type: #{type}"
  15. end
  16. 8 @times = m[1].to_i
  17. 8 @sides = m[2].to_i
  18. end
  19. # 表を振る
  20. # @param randomizer [#roll_sum] ランダマイザ
  21. # @return [String] 結果
  22. 1 def roll(randomizer)
  23. 26 value = randomizer.roll_sum(@times, @sides)
  24. 26 index = value - @times
  25. 26 chosen = @items[index]
  26. 76 then: 22 else: 28 body = chosen.map { |item| item.respond_to?(:roll) ? item.roll(randomizer) : item }.join("\n")
  27. 26 return "#{@name}(#{value}) > #{body}"
  28. end
  29. end
  30. end
  31. end
  32. end

lib/bcdice/game_system/beginning_idol/costume_table.rb

100.0% lines covered

100.0% branches covered

16 relevant lines. 16 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BeginningIdol < Base
  5. 1 class CostumeTable
  6. 1 def self.from_i18n(key, locale)
  7. 6 table = I18n.t(key, locale: locale)
  8. 6 new(table[:name], table[:items])
  9. end
  10. # @param name [String]
  11. # @param items [Hash{Integer => String}]
  12. 1 def initialize(name, items)
  13. 6 @name = name
  14. 6 @items = items
  15. end
  16. # @param randomizer [Randomizer]
  17. # @return [String]
  18. 1 def roll(randomizer)
  19. 10 value = randomizer.roll_d66(D66SortType::ASC)
  20. 10 "#{@name}(#{value}) > #{@items[value]}"
  21. end
  22. # @return [DiceTable::D66Table]
  23. 1 def brand_only()
  24. 12 DiceTable::D66Table.new(
  25. @name,
  26. D66SortType::ASC,
  27. 252 @items.transform_values { |e| e.split("\n").first }
  28. )
  29. end
  30. end
  31. end
  32. end
  33. end

lib/bcdice/game_system/beginning_idol/d6_twice_table.rb

100.0% lines covered

100.0% branches covered

16 relevant lines. 16 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BeginningIdol < Base
  5. 1 class D6TwiceTable
  6. # @param key [String]
  7. # @param locale [Symbol]
  8. # @return [D6TwiceTable]
  9. 1 def self.from_i18n(key, locale)
  10. 12 table = I18n.t(key, locale: locale)
  11. 12 new(table[:name], table[:items1], table[:items2])
  12. end
  13. # @param name [String]
  14. # @param items1 [Array<String>]
  15. # @param items2 [Array<String>]
  16. 1 def initialize(name, items1, items2)
  17. 12 @name = name
  18. 12 @items1 = items1
  19. 12 @items2 = items2
  20. end
  21. # @param [Randomizer]
  22. # @return [String]
  23. 1 def roll(randomizer)
  24. 20 value1, value2 = randomizer.roll_barabara(2, 6)
  25. 20 chosen1 = @items1[value1 - 1]
  26. 20 chosen2 = @items2[value2 - 1]
  27. 20 "#{@name}[#{value1},#{value2}] > #{chosen1}#{chosen2}"
  28. end
  29. end
  30. end
  31. end
  32. end

lib/bcdice/game_system/beginning_idol/item_table.rb

100.0% lines covered

100.0% branches covered

26 relevant lines. 26 lines covered and 0 lines missed.
10 total branches, 10 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BeginningIdol < Base
  5. 1 class ItemTable
  6. 1 def initialize(locale)
  7. 4 @locale = locale
  8. end
  9. 1 def roll_command(randomizer, command)
  10. 303 m = /^IT(\d+)?$/.match(command)
  11. 303 else: 10 then: 293 unless m
  12. 293 return nil
  13. end
  14. 10 then: 8 else: 2 roll_counts = m[1]&.to_i || 1
  15. 10 return roll(randomizer, roll_counts)
  16. end
  17. # @param randomizer [BCDice::Randomizer]
  18. # @param counts [Integer]
  19. 1 def roll(randomizer, roll_counts = 1)
  20. 14 then: 2 else: 12 if roll_counts == 0
  21. 2 return nil
  22. end
  23. 12 table = I18n.t("BeginningIdol.item_table", locale: @locale)
  24. 12 dice_list = randomizer.roll_barabara(roll_counts, 6).sort
  25. 12 grouped = dice_list.group_by(&:itself)
  26. 12 item_list = grouped.map do |dice, list|
  27. 24 item = table[:items][dice - 1]
  28. 24 then: 16 else: 8 if grouped.size != 1
  29. 16 item = format(table[:emph], item: item)
  30. end
  31. 24 then: 12 if dice_list.size == grouped.size
  32. 12 item
  33. else: 12 else
  34. 12 format(table[:counting], item: item, count: list.size)
  35. end
  36. end
  37. 12 return "#{table[:name]} > [#{dice_list.join(',')}] > #{item_list.join(table[:sep])}"
  38. end
  39. end
  40. end
  41. end
  42. end

lib/bcdice/game_system/beginning_idol/my_skill_name_table.rb

100.0% lines covered

100.0% branches covered

20 relevant lines. 20 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BeginningIdol < Base
  5. 1 class MySkillNameTable
  6. # @param locale [Symbol]
  7. # @return [MySkillNameTable]
  8. 1 def initialize(locale)
  9. 2 @locale = locale
  10. 2 article = DiceTable::Table.from_i18n("BeginningIdol.MS.subtables.article", locale)
  11. 2 describe = DiceTable::D66Table.from_i18n("BeginningIdol.MS.subtables.describe", locale)
  12. 2 scene = DiceTable::D66Table.from_i18n("BeginningIdol.MS.subtables.scene", locale)
  13. 2 material = DiceTable::D66Table.from_i18n("BeginningIdol.MS.subtables.material", locale)
  14. 2 action = DiceTable::D66Table.from_i18n("BeginningIdol.MS.subtables.action", locale)
  15. @chains = [
  16. 2 [describe, scene, material],
  17. [describe, scene, action],
  18. [describe, material, action],
  19. [scene, material, action],
  20. [describe, scene, article],
  21. [material, action, article],
  22. ].freeze
  23. end
  24. # @param randomizer [BCDice::Randomizer]
  25. # @return [String]
  26. 1 def roll(randomizer)
  27. 4 index = randomizer.roll_once(6)
  28. 16 chosens = @chains[index - 1].map { |t| t.roll(randomizer) }
  29. 16 dice = chosens.map { |chosen| chosen.table_name + chosen.value.to_s }
  30. 4 name = I18n.t("BeginningIdol.MS.name", locale: @locale)
  31. 4 skill_name_format = I18n.t("BeginningIdol.MS.formats", locale: @locale)[index - 1]
  32. 4 skill_name = format(skill_name_format, *chosens.map(&:body))
  33. 4 "#{name} > [#{index},#{dice.join(',')}] > #{skill_name}"
  34. end
  35. end
  36. end
  37. end
  38. end

lib/bcdice/game_system/beginning_idol/random_event_table.rb

100.0% lines covered

100.0% branches covered

15 relevant lines. 15 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BeginningIdol < Base
  5. 1 class RandomEventTable
  6. # @param locale [Symbol]
  7. # @return [MySkillNameTable]
  8. 1 def initialize(locale)
  9. 2 @locale = locale
  10. end
  11. # @param randomizer [BCDice::Randomizer]
  12. # @return [String]
  13. 1 def roll(randomizer)
  14. 2 first_index = randomizer.roll_once(6)
  15. 2 d66_index = randomizer.roll_d66(D66SortType::NO_SORT)
  16. 2 then: 1 else: 1 i18n_key = first_index.even? ? "BeginningIdol.RE.on_event" : "BeginningIdol.RE.off_event"
  17. 2 table = I18n.t(i18n_key, locale: @locale)
  18. 2 name = I18n.t("BeginningIdol.RE.name", locale: @locale)
  19. 2 result_format = I18n.t("BeginningIdol.RE.format", locale: @locale)
  20. 2 chosen = table[:items][d66_index]
  21. 2 return "#{name} > (1D6) > #{first_index}\n#{table[:name]} > [#{d66_index}] > #{format(result_format, event: chosen[0], page: chosen[1])}"
  22. end
  23. end
  24. end
  25. end
  26. end

lib/bcdice/game_system/beginning_idol/skill_table.rb

100.0% lines covered

100.0% branches covered

36 relevant lines. 36 lines covered and 0 lines missed.
4 total branches, 4 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BeginningIdol < Base
  5. 1 class SkillTable < DiceTable::SaiFicSkillTable
  6. 1 def roll(randomizer)
  7. 2 roll_command(randomizer, "RTT")
  8. end
  9. end
  10. 1 class SkillGetTable < DiceTable::Table
  11. 1 def self.from_i18n(key, skill_table, locale)
  12. 4 table = I18n.t(key, locale: locale)
  13. 4 new(table[:name], table[:type], table[:items], skill_table, locale)
  14. end
  15. 1 def initialize(name, type, items, skill_table, locale)
  16. 4 super(name, type, items)
  17. 4 @skill_table = skill_table
  18. 4 skill_get_table = I18n.t("BeginningIdol.skill_get_table", locale: locale)
  19. 4 @reroll_reg = Regexp.new(skill_get_table[:reroll_reg])
  20. 4 @reroll = skill_get_table[:reroll]
  21. 4 @secondary_name = skill_get_table[:secondary_name]
  22. end
  23. 1 def roll(randomizer)
  24. 8 chosen = super(randomizer)
  25. 8 m = @reroll_reg.match(chosen.body)
  26. 8 else: 4 then: 4 unless m
  27. 4 return chosen
  28. end
  29. 4 reroll_category = m.captures
  30. 4 body = chosen.body + "\n"
  31. 4 loop do
  32. 16 skill = @skill_table.roll_skill(randomizer)
  33. 16 body += "#{@secondary_name} > [#{skill.category_dice},#{skill.row_dice}] > #{skill}"
  34. 16 else: 12 then: 4 unless reroll_category.include?(skill.category_name)
  35. 4 break
  36. end
  37. 12 body += " > #{@reroll}\n"
  38. end
  39. 4 DiceTable::RollResult.new(chosen.table_name, chosen.value, body)
  40. end
  41. end
  42. 1 class SkillHometown
  43. 1 def initialize(skill_table)
  44. 2 @skill_name = skill_table
  45. end
  46. 1 def roll(randomizer)
  47. 2 @skill_name.roll_command(randomizer, "AT6")
  48. end
  49. end
  50. end
  51. end
  52. end

lib/bcdice/game_system/beginning_idol/table.rb

100.0% lines covered

100.0% branches covered

50 relevant lines. 50 lines covered and 0 lines missed.
6 total branches, 6 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/game_system/beginning_idol/chain_table"
  3. 1 require "bcdice/game_system/beginning_idol/chain_d66_table"
  4. 1 require "bcdice/game_system/beginning_idol/bad_status_table"
  5. 1 require "bcdice/game_system/beginning_idol/random_event_table"
  6. 1 require "bcdice/game_system/beginning_idol/my_skill_name_table"
  7. 1 require "bcdice/game_system/beginning_idol/d6_twice_table"
  8. 1 require "bcdice/game_system/beginning_idol/item_table"
  9. 1 require "bcdice/game_system/beginning_idol/costume_table"
  10. 1 require "bcdice/game_system/beginning_idol/accessories_table"
  11. 1 require "bcdice/game_system/beginning_idol/with_abnormality"
  12. 1 require "bcdice/game_system/beginning_idol/work_table"
  13. 1 require "bcdice/game_system/beginning_idol/skill_table"
  14. 1 module BCDice
  15. 1 module GameSystem
  16. 1 class BeginningIdol < Base
  17. 1 class << self
  18. 1 private
  19. 1 def translate_skill_table(locale)
  20. 4 SkillTable.from_i18n(
  21. "BeginningIdol.skill_table",
  22. locale,
  23. rtt: "AT",
  24. rttn: ["AT1", "AT2", "AT3", "AT4", "AT5", "AT6"]
  25. )
  26. end
  27. 1 def translate_tables(locale)
  28. 2 costume_challenge_girls = CostumeTable.from_i18n("BeginningIdol.tables.DT", locale)
  29. 2 costume_road_to_prince = CostumeTable.from_i18n("BeginningIdol.tables.RC", locale)
  30. 2 costume_fortune_stars = CostumeTable.from_i18n("BeginningIdol.tables.FC", locale)
  31. 2 bland = ChainTable.new(
  32. I18n.t("BeginningIdol.ACB.name", locale: locale),
  33. "1D6",
  34. [
  35. [I18n.t("BeginningIdol.ACB.items.challenge_girls", locale: locale), costume_challenge_girls.brand_only()],
  36. [I18n.t("BeginningIdol.ACB.items.challenge_girls", locale: locale), costume_challenge_girls.brand_only()],
  37. [I18n.t("BeginningIdol.ACB.items.road_to_prince", locale: locale), costume_road_to_prince.brand_only()],
  38. [I18n.t("BeginningIdol.ACB.items.road_to_prince", locale: locale), costume_road_to_prince.brand_only()],
  39. [I18n.t("BeginningIdol.ACB.items.fortune_stars", locale: locale), costume_fortune_stars.brand_only()],
  40. [I18n.t("BeginningIdol.ACB.items.fortune_stars", locale: locale), costume_fortune_stars.brand_only()],
  41. ]
  42. )
  43. 2 bad_status_table = BadStatusTable.new(locale)
  44. 2 skill_table = translate_skill_table(locale)
  45. 2 rare_skill_table = DiceTable::Table.from_i18n("BeginningIdol.rare_skill_table", locale)
  46. 2 item_table = ItemTable.new(locale)
  47. 2 tn = ChainTable.new(
  48. I18n.t("BeginningIdol.TN.name", locale: locale),
  49. "1D6",
  50. 2 I18n.t("BeginningIdol.TN.items", locale: locale).dup.tap { |items| items[3].push(skill_table) }
  51. )
  52. 2 cg = ChainTable.new(
  53. I18n.t("BeginningIdol.CG.name", locale: locale),
  54. "1D6",
  55. I18n.t("BeginningIdol.CG.items", locale: locale).map.with_index do |item, index|
  56. 12 then: 4 if [3, 4].include?(index)
  57. 4 [item, item_table]
  58. else: 8 else
  59. 8 [item]
  60. end
  61. end
  62. )
  63. 2 gg = ChainD66Table.new(
  64. I18n.t("BeginningIdol.GG.name", locale: locale),
  65. I18n.t("BeginningIdol.GG.items", locale: locale).to_h do |index, value|
  66. chain =
  67. 42 then: 6 if [23, 24, 25].include?(index)
  68. 6 else: 36 [value, rare_skill_table]
  69. 36 then: 2 elsif index == 56
  70. 2 [value, item_table]
  71. else: 34 else
  72. 34 [value]
  73. end
  74. 42 [index, chain]
  75. end
  76. )
  77. 2 ha = ChainD66Table.new(
  78. I18n.t("BeginningIdol.HA.name", locale: locale),
  79. 2 I18n.t("BeginningIdol.HA.items", locale: locale).dup.tap { |items| items[22].push(SkillHometown.new(skill_table)) }
  80. )
  81. {
  82. 2 "DT" => costume_challenge_girls,
  83. "RC" => costume_road_to_prince,
  84. "FC" => costume_fortune_stars,
  85. "ACB" => bland,
  86. "TN" => tn,
  87. "CG" => cg,
  88. "GG" => gg,
  89. "HA" => ha,
  90. "CBT" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.CBT", locale),
  91. "RCB" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.RCB", locale),
  92. "HBT" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.HBT", locale),
  93. "RHB" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.RHB", locale),
  94. "RU" => DiceTable::Table.from_i18n("BeginningIdol.tables.RU", locale),
  95. "SIP" => DiceTable::Table.from_i18n("BeginningIdol.tables.SIP", locale),
  96. "BU" => DiceTable::Table.from_i18n("BeginningIdol.tables.BU", locale),
  97. "HW" => DiceTable::Table.from_i18n("BeginningIdol.tables.HW", locale),
  98. "FL" => DiceTable::Table.from_i18n("BeginningIdol.tables.FL", locale),
  99. "MSE" => DiceTable::Table.from_i18n("BeginningIdol.tables.MSE", locale),
  100. "ST" => DiceTable::Table.from_i18n("BeginningIdol.tables.ST", locale),
  101. "FST" => DiceTable::Table.from_i18n("BeginningIdol.tables.FST", locale),
  102. "BWT" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.BWT", locale),
  103. "LWT" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.LWT", locale),
  104. "TWT" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.TWT", locale),
  105. "CWT" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.CWT", locale),
  106. "SU" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.SU", locale),
  107. "WI" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.WI", locale),
  108. "NA" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.NA", locale),
  109. "GA" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.GA", locale),
  110. "BA" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.BA", locale),
  111. "WT" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.WT", locale),
  112. "VA" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.VA", locale),
  113. "MU" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.MU", locale),
  114. "DR" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.DR", locale),
  115. "VI" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.VI", locale),
  116. "SP" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.SP", locale),
  117. "CHR" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.CHR", locale),
  118. "PAR" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.PAR", locale),
  119. "SW" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.SW", locale),
  120. "AN" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.AN", locale),
  121. "MOV" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.MOV", locale),
  122. "FA" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.FA", locale),
  123. "BVT" => DiceTable::Table.from_i18n("BeginningIdol.tables.BVT", locale),
  124. "LVT" => DiceTable::Table.from_i18n("BeginningIdol.tables.LVT", locale),
  125. "TVT" => DiceTable::Table.from_i18n("BeginningIdol.tables.TVT", locale),
  126. "CVT" => DiceTable::Table.from_i18n("BeginningIdol.tables.CVT", locale),
  127. "BST" => DiceTable::Table.from_i18n("BeginningIdol.tables.BST", locale),
  128. "LST" => DiceTable::Table.from_i18n("BeginningIdol.tables.LST", locale),
  129. "TST" => DiceTable::Table.from_i18n("BeginningIdol.tables.TST", locale),
  130. "CST" => DiceTable::Table.from_i18n("BeginningIdol.tables.CST", locale),
  131. "BPT" => DiceTable::Table.from_i18n("BeginningIdol.tables.BPT", locale),
  132. "LPT" => DiceTable::Table.from_i18n("BeginningIdol.tables.LPT", locale),
  133. "TPT" => DiceTable::Table.from_i18n("BeginningIdol.tables.TPT", locale),
  134. "CPT" => DiceTable::Table.from_i18n("BeginningIdol.tables.CPT", locale),
  135. "BIT" => DiceTable::Table.from_i18n("BeginningIdol.tables.BIT", locale),
  136. "LIT" => DiceTable::Table.from_i18n("BeginningIdol.tables.LIT", locale),
  137. "TIT" => DiceTable::Table.from_i18n("BeginningIdol.tables.TIT", locale),
  138. "CIT" => DiceTable::Table.from_i18n("BeginningIdol.tables.CIT", locale),
  139. "CHO" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.CHO", locale),
  140. "SCH" => DiceTable::Table.from_i18n("BeginningIdol.tables.SCH", locale),
  141. "WCH" => DiceTable::Table.from_i18n("BeginningIdol.tables.WCH", locale),
  142. "NCH" => DiceTable::Table.from_i18n("BeginningIdol.tables.NCH", locale),
  143. "GCH" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.GCH", locale),
  144. "PCH" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.PCH", locale),
  145. "LUR" => D6TwiceTable.from_i18n("BeginningIdol.tables.LUR", locale),
  146. "SUR" => D6TwiceTable.from_i18n("BeginningIdol.tables.SUR", locale),
  147. "WUR" => D6TwiceTable.from_i18n("BeginningIdol.tables.WUR", locale),
  148. "NUR" => D6TwiceTable.from_i18n("BeginningIdol.tables.NUR", locale),
  149. "GUR" => D6TwiceTable.from_i18n("BeginningIdol.tables.GUR", locale),
  150. "BUR" => D6TwiceTable.from_i18n("BeginningIdol.tables.BUR", locale),
  151. "ACE" => DiceTable::D66Table.from_i18n("BeginningIdol.tables.ACE", locale),
  152. "ACT" => translate_accessories_table(locale),
  153. "MS" => MySkillNameTable.new(locale),
  154. "RE" => RandomEventTable.new(locale),
  155. "SH" => D66WithAbnormality.from_i18n("BeginningIdol.tables.SH", bad_status_table, locale),
  156. "MO" => D66WithAbnormality.from_i18n("BeginningIdol.tables.MO", bad_status_table, locale),
  157. "SEA" => D66WithAbnormality.from_i18n("BeginningIdol.tables.SEA", bad_status_table, locale),
  158. "SPA" => D66WithAbnormality.from_i18n("BeginningIdol.tables.SPA", bad_status_table, locale),
  159. "LN" => TableWithAbnormality.from_i18n("BeginningIdol.tables.LN", bad_status_table, locale),
  160. "SGT" => SkillGetTable.from_i18n("BeginningIdol.tables.SGT", skill_table, locale),
  161. "RS" => SkillGetTable.from_i18n("BeginningIdol.tables.RS", skill_table, locale),
  162. }
  163. end
  164. end
  165. 1 TABLES = translate_tables(:ja_jp)
  166. 1 BAD_STATUS_TABLE = BadStatusTable.new(:ja_jp)
  167. 1 LOCAL_WORK_TABLE = translate_local_work_table(:ja_jp)
  168. 1 ITEM_TABLE = ItemTable.new(:ja_jp)
  169. 1 SKILL_TABLE = translate_skill_table(:ja_jp)
  170. 1 register_prefix(TABLES.keys)
  171. end
  172. end
  173. end

lib/bcdice/game_system/beginning_idol/with_abnormality.rb

97.67% lines covered

66.67% branches covered

43 relevant lines. 42 lines covered and 1 lines missed.
6 total branches, 4 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BeginningIdol < Base
  5. 1 module WithAbnormality
  6. 1 def replace_abnormality(chosen, randomizer)
  7. 21 reg = Regexp.new(I18n.t("BeginningIdol.abnormality.regexp", locale: @locale))
  8. 21 m = reg.match(chosen.body)
  9. 21 else: 9 then: 12 unless m
  10. 12 return chosen
  11. end
  12. 9 abno_count = kanji_to_i(m[1])
  13. 9 else: 9 then: 0 unless abno_count
  14. return chosen
  15. end
  16. 9 text = @bad_status_table.roll(randomizer, abno_count)
  17. 9 new_body = chosen.body.sub(reg, text)
  18. 9 return DiceTable::RollResult.new(chosen.table_name, chosen.value, new_body)
  19. end
  20. 1 def kanji_to_i(kanji)
  21. 9 list = I18n.t("BeginningIdol.abnormality.num_map", locale: @locale)
  22. 9 then: 9 else: 0 list.find_index(kanji)&.succ
  23. end
  24. end
  25. 1 class D66WithAbnormality < DiceTable::D66Table
  26. 1 include WithAbnormality
  27. 1 def self.from_i18n(key, bad_status_table, locale)
  28. 8 table = I18n.t(key, locale: locale)
  29. 8 sort_type = D66SortType.const_get(table[:d66_sort_type])
  30. 8 new(table[:name], sort_type, table[:items], bad_status_table, locale)
  31. end
  32. 1 def initialize(name, sort_type, items, bad_status_table, locale)
  33. 8 super(name, sort_type, items)
  34. 8 @bad_status_table = bad_status_table
  35. 8 @locale = locale
  36. end
  37. 1 def roll(randomizer)
  38. 17 chosen = super(randomizer)
  39. 17 replace_abnormality(chosen, randomizer)
  40. end
  41. end
  42. 1 class TableWithAbnormality < DiceTable::Table
  43. 1 include WithAbnormality
  44. 1 def self.from_i18n(key, bad_status_table, locale)
  45. 2 table = I18n.t(key, locale: locale)
  46. 2 new(table[:name], table[:type], table[:items], bad_status_table, locale)
  47. end
  48. 1 def initialize(name, type, items, bad_status_table, locale)
  49. 2 super(name, type, items)
  50. 2 @bad_status_table = bad_status_table
  51. 2 @locale = locale
  52. end
  53. 1 def roll(randomizer)
  54. 4 chosen = super(randomizer)
  55. 4 replace_abnormality(chosen, randomizer)
  56. end
  57. end
  58. end
  59. end
  60. end

lib/bcdice/game_system/beginning_idol/work_table.rb

96.88% lines covered

90.0% branches covered

32 relevant lines. 31 lines covered and 1 lines missed.
10 total branches, 9 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class BeginningIdol < Base
  5. 1 class WorkWithChanceTable < DiceTable::D66Table
  6. 1 def self.from_i18n(key, locale)
  7. 2 table = I18n.t(key, locale: locale)
  8. 2 sort_type = D66SortType.const_get(table[:d66_sort_type])
  9. 2 new(table[:name], sort_type, table[:items], locale)
  10. end
  11. 1 def initialize(name, sort_type, items, locale)
  12. 2 super(name, sort_type, items)
  13. 2 @regexp = Regexp.new(I18n.t("BeginningIdol.with_chance.regexp", locale: locale))
  14. 2 @off = I18n.t("BeginningIdol.with_chance.off_text", locale: locale)
  15. end
  16. 1 def roll_command(randomizer, command)
  17. 289 m = /^LO([1-6]{1,2})?$/.match(command)
  18. 289 else: 8 then: 281 unless m
  19. 281 return nil
  20. end
  21. 8 then: 4 else: 4 roll(randomizer, m[1]&.to_i)
  22. end
  23. 1 def roll(randomizer, chance = nil)
  24. 8 chosen = super(randomizer)
  25. 8 else: 4 then: 4 unless chance
  26. 4 return chosen
  27. end
  28. 4 m = @regexp.match(chosen.body)
  29. 4 then: 2 if m && m[1].to_i >= chance
  30. 2 else: 2 DiceTable::RollResult.new(chosen.table_name, chosen.value, @off)
  31. 2 then: 2 elsif m
  32. 2 DiceTable::RollResult.new(chosen.table_name, chosen.value, chosen.body.sub(@regexp, ""))
  33. else: 0 else
  34. chosen
  35. end
  36. end
  37. end
  38. 1 class << self
  39. 1 private
  40. 1 def translate_local_work_table(locale)
  41. 2 WorkWithChanceTable.from_i18n("BeginningIdol.local_work", locale)
  42. end
  43. end
  44. 1 register_prefix("LO")
  45. end
  46. end
  47. end

lib/bcdice/game_system/cthulhu7th/full_auto.rb

99.32% lines covered

95.0% branches covered

148 relevant lines. 147 lines covered and 1 lines missed.
60 total branches, 57 branches covered and 3 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Cthulhu7th < Base
  5. 1 class FullAuto
  6. 1 BONUS_DICE_RANGE = (-2..2).freeze
  7. # 連射処理を止める条件(難易度の閾値)
  8. # @return [Hash<String, Integer>]
  9. #
  10. # 成功の種類の小文字表記 => 難易度の閾値
  11. 1 ROLL_FULL_AUTO_DIFFICULTY_THRESHOLD = {
  12. # レギュラー
  13. "r" => 0,
  14. # ハード
  15. "h" => 1,
  16. # イクストリーム
  17. "e" => 2
  18. }.freeze
  19. 1 def self.eval(command, randomizer)
  20. 76 new.eval(command, randomizer)
  21. end
  22. 1 def eval(command, randomizer)
  23. 76 @randomizer = randomizer
  24. 76 getFullAutoResult(command)
  25. end
  26. 1 private
  27. 1 include Rollable
  28. 1 def getFullAutoResult(command)
  29. 76 m = /^FAR\((-?\d+),(-?\d+),(-?\d+)(?:,(-?\d+)?)?(?:,(-?\w+)?)?(?:,(-?\d+)?)?\)$/i.match(command)
  30. 76 else: 76 then: 0 unless m
  31. return nil
  32. end
  33. 76 bullet_count = m[1].to_i
  34. 76 diff = m[2].to_i
  35. 76 broken_number = m[3].to_i
  36. 76 bonus_dice_count = m[4].to_i
  37. 76 then: 25 else: 51 stop_count = m[5]&.downcase || ""
  38. 76 then: 21 else: 55 bullet_set_count_cap = m[6]&.to_i || diff / 10
  39. 76 output = ""
  40. # 最大で(8回*(PC技能値最大値/10))=72発しか撃てないはずなので上限
  41. 76 bullet_count_limit = 100
  42. 76 then: 2 else: 74 if bullet_count > bullet_count_limit
  43. 2 output += "弾薬が多すぎます。装填された弾薬を#{bullet_count_limit}発に変更します。\n"
  44. 2 bullet_count = bullet_count_limit
  45. end
  46. # ボレーの上限の設定がおかしい場合の注意表示
  47. 76 then: 2 if (bullet_set_count_cap > diff / 10) && (diff > 39) && !m[6].nil?
  48. 2 bullet_set_count_cap = diff / 10
  49. 2 else: 74 output += "ボレーの弾丸の数の上限は\[技能値÷10(切り捨て)\]発なので、それより高い数を指定できません。ボレーの弾丸の数を#{bullet_set_count_cap}発に変更します。\n"
  50. 74 then: 2 else: 72 elsif (diff <= 39) && (bullet_set_count_cap > 3) && !m[6].nil?
  51. 2 bullet_set_count_cap = 3
  52. 2 output += "技能値が39以下ではボレーの弾丸の数の上限および下限は3発です。ボレーの弾丸の数を#{bullet_set_count_cap}発に変更します。\n"
  53. end
  54. # ボレーの下限の設定がおかしい場合の注意表示およびエラー表示
  55. 76 then: 2 else: 74 return "ボレーの弾丸の数は正の数です。" if (bullet_set_count_cap <= 0) && !m[6].nil?
  56. 74 then: 5 else: 69 if (bullet_set_count_cap < 3) && !m[6].nil?
  57. 5 bullet_set_count_cap = 3
  58. 5 output += "ボレーの弾丸の数の下限は3発です。ボレーの弾丸の数を3発に変更します。\n"
  59. end
  60. 74 then: 2 else: 72 return "弾薬は正の数です。" if bullet_count <= 0
  61. 72 then: 1 else: 71 return "目標値は正の数です。" if diff <= 0
  62. 71 then: 1 else: 70 if broken_number < 0
  63. 1 output += "故障ナンバーは正の数です。マイナス記号を外します。\n"
  64. 1 broken_number = broken_number.abs
  65. end
  66. 71 else: 69 then: 2 unless BONUS_DICE_RANGE.include?(bonus_dice_count)
  67. 2 return "エラー。ボーナス・ペナルティダイスの値は#{BONUS_DICE_RANGE.min}~#{BONUS_DICE_RANGE.max}です。"
  68. end
  69. 69 output += "ボーナス・ペナルティダイス[#{bonus_dice_count}]"
  70. 69 output += rollFullAuto(bullet_count, diff, broken_number, bonus_dice_count, stop_count, bullet_set_count_cap)
  71. 69 return output
  72. end
  73. 1 def rollFullAuto(bullet_count, diff, broken_number, dice_num, stop_count, bullet_set_count_cap)
  74. 69 output = ""
  75. 69 loopCount = 0
  76. 69 counts = {
  77. hit_bullet: 0,
  78. impale_bullet: 0,
  79. bullet: bullet_count,
  80. }
  81. # 難易度変更用ループ
  82. 69 4.times do |more_difficulty|
  83. 90 output += getNextDifficultyMessage(more_difficulty)
  84. # ペナルティダイスを減らしながらロール用ループ
  85. 90 while dice_num >= BONUS_DICE_RANGE.min
  86. body: 157
  87. 157 loopCount += 1
  88. 157 hit_result, total, total_list = getHitResultInfos(dice_num, diff, more_difficulty)
  89. 157 output += "\n#{loopCount}回目: > #{total_list.join(', ')} > #{hit_result}"
  90. 157 then: 27 else: 130 if total >= broken_number
  91. 27 output += " ジャム"
  92. 27 return getHitResultText(output, counts)
  93. end
  94. 130 hit_type = getHitType(more_difficulty, hit_result)
  95. 130 hit_bullet, impale_bullet, lost_bullet = getBulletResults(counts[:bullet], hit_type, diff, bullet_set_count_cap)
  96. 130 output += " (#{hit_bullet}発が命中、#{impale_bullet}発が貫通)"
  97. 130 counts[:hit_bullet] += hit_bullet
  98. 130 counts[:impale_bullet] += impale_bullet
  99. 130 counts[:bullet] -= lost_bullet
  100. 130 then: 24 else: 106 return getHitResultText(output, counts) if counts[:bullet] <= 0
  101. 106 dice_num -= 1
  102. end
  103. # 指定された難易度となった場合、連射処理を途中で止める
  104. 39 then: 15 else: 24 if shouldStopRollFullAuto?(stop_count, more_difficulty)
  105. 15 output += "\n【指定の難易度となったので、処理を終了します。】"
  106. 15 break
  107. end
  108. 24 dice_num += 1
  109. end
  110. 18 return getHitResultText(output, counts)
  111. end
  112. # 連射処理を止めるべきかどうかを返す
  113. # @param [String] stop_count 成功の種類
  114. # @param [Integer] difficulty 難易度
  115. # @return [Boolean]
  116. 1 def shouldStopRollFullAuto?(stop_count, difficulty)
  117. 39 difficulty_threshold = ROLL_FULL_AUTO_DIFFICULTY_THRESHOLD[stop_count]
  118. 39 return difficulty_threshold && difficulty >= difficulty_threshold
  119. end
  120. 1 def getHitResultInfos(dice_num, diff, more_difficulty)
  121. 157 total, total_list = roll_with_bonus(dice_num)
  122. 157 fumbleable = getFumbleable(more_difficulty)
  123. 157 hit_result = ResultLevel.from_values(total, diff, fumbleable).to_s
  124. 157 return hit_result, total, total_list
  125. end
  126. 1 def getHitResultText(output, counts)
  127. 69 return "#{output}\n> #{counts[:hit_bullet]}発が通常命中、#{counts[:impale_bullet]}発が貫通、残弾#{counts[:bullet]}発"
  128. end
  129. 1 def getHitType(more_difficulty, hit_result)
  130. 130 successList, impaleBulletList = getSuccessListImpaleBulletList(more_difficulty)
  131. 130 then: 54 else: 76 return :hit if successList.include?(hit_result)
  132. 76 then: 38 else: 38 return :impale if impaleBulletList.include?(hit_result)
  133. 38 return ""
  134. end
  135. 1 def getBulletResults(bullet_count, hit_type, diff, bullet_set_count_cap)
  136. 130 bullet_set_count = getSetOfBullet(diff, bullet_set_count_cap)
  137. 130 hit_bullet_count_base = getHitBulletCountBase(diff, bullet_set_count)
  138. 130 impale_bullet_count_base = (bullet_set_count / 2.to_f)
  139. 130 lost_bullet_count = 0
  140. 130 hit_bullet_count = 0
  141. 130 impale_bullet_count = 0
  142. 130 if !isLastBulletTurn(bullet_count, bullet_set_count)
  143. then: 116
  144. 116 else: 38 case hit_type
  145. when: 45 when :hit
  146. 45 hit_bullet_count = hit_bullet_count_base # 通常命中した弾数の計算
  147. when: 33 when :impale
  148. 33 impale_bullet_count = impale_bullet_count_base.floor # 貫通した弾数の計算
  149. 33 hit_bullet_count = impale_bullet_count_base.ceil
  150. end
  151. 116 lost_bullet_count = bullet_set_count
  152. else
  153. else: 14
  154. 14 else: 0 case hit_type
  155. when: 9 when :hit
  156. 9 hit_bullet_count = getLastHitBulletCount(bullet_count)
  157. when: 5 when :impale
  158. 5 impale_bullet_count = getLastHitBulletCount(bullet_count)
  159. 5 hit_bullet_count = bullet_count - impale_bullet_count
  160. end
  161. 14 lost_bullet_count = bullet_count
  162. end
  163. 130 return hit_bullet_count, impale_bullet_count, lost_bullet_count
  164. end
  165. 1 def getSuccessListImpaleBulletList(more_difficulty)
  166. 130 successList = []
  167. 130 impaleBulletList = []
  168. 130 else: 0 case more_difficulty
  169. when: 117 when 0
  170. 117 successList = ["ハード成功", "レギュラー成功"]
  171. 117 impaleBulletList = ["クリティカル", "イクストリーム成功"]
  172. when: 6 when 1
  173. 6 successList = ["ハード成功"]
  174. 6 impaleBulletList = ["クリティカル", "イクストリーム成功"]
  175. when: 4 when 2
  176. 4 successList = []
  177. 4 impaleBulletList = ["クリティカル", "イクストリーム成功"]
  178. when: 3 when 3
  179. 3 successList = ["クリティカル"]
  180. 3 impaleBulletList = []
  181. end
  182. 130 return successList, impaleBulletList
  183. end
  184. 1 def getNextDifficultyMessage(more_difficulty)
  185. 90 else: 69 case more_difficulty
  186. when: 13 when 1
  187. 13 return "\n【難易度がハードに変更】"
  188. when: 5 when 2
  189. 5 return "\n【難易度がイクストリームに変更】"
  190. when: 3 when 3
  191. 3 return "\n【難易度がクリティカルに変更】"
  192. end
  193. 69 return ""
  194. end
  195. 1 def getSetOfBullet(diff, bullet_set_count_cap)
  196. 130 bullet_set_count = diff / 10
  197. 130 then: 10 else: 120 if bullet_set_count_cap < bullet_set_count
  198. 10 bullet_set_count = bullet_set_count_cap
  199. end
  200. 130 then: 21 else: 109 if (diff >= 1) && (diff < 30)
  201. 21 bullet_set_count = 3 # 技能値が29以下での最低値保障処理
  202. end
  203. 130 return bullet_set_count
  204. end
  205. 1 def getHitBulletCountBase(diff, bullet_set_count)
  206. 130 hit_bullet_count_base = (bullet_set_count / 2)
  207. 130 then: 21 else: 109 if (diff >= 1) && (diff < 30)
  208. 21 hit_bullet_count_base = 1 # 技能値29以下での最低値保障
  209. end
  210. 130 return hit_bullet_count_base
  211. end
  212. 1 def isLastBulletTurn(bullet_count, bullet_set_count)
  213. 130 ((bullet_count - bullet_set_count) < 0)
  214. end
  215. 1 def getLastHitBulletCount(bullet_count)
  216. # 残弾1での最低値保障処理
  217. 14 then: 5 else: 9 if bullet_count == 1
  218. 5 return 1
  219. end
  220. 9 count = (bullet_count / 2.to_f).floor
  221. 9 return count
  222. end
  223. 1 def getFumbleable(more_difficulty)
  224. # 成功が49以下の出目のみとなるため、ファンブル値は上昇
  225. 157 return (more_difficulty >= 1)
  226. end
  227. end
  228. end
  229. end
  230. end

lib/bcdice/game_system/cthulhu7th/rollable.rb

100.0% lines covered

100.0% branches covered

19 relevant lines. 19 lines covered and 0 lines missed.
6 total branches, 6 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Cthulhu7th < Base
  5. 1 module Rollable
  6. 1 private
  7. # 1D100の一の位用のダイスロール
  8. # 0から9までの値を返す
  9. #
  10. # @return [Integer]
  11. 1 def roll_ones_d10
  12. 205 dice = @randomizer.roll_once(10)
  13. 205 then: 27 else: 178 return 0 if dice == 10
  14. 178 return dice
  15. end
  16. # @param bonus [Integer] ボーナス・ペナルティダイスの数。負の数ならペナルティダイス。
  17. # @return [Array<(Integer, Array<Integer>)>]
  18. 1 def roll_with_bonus(bonus)
  19. 615 tens_list = Array.new(bonus.abs + 1) { @randomizer.roll_tens_d10 }
  20. 205 ones = roll_ones_d10()
  21. 205 dice_list = tens_list.map do |tens|
  22. 410 dice = tens + ones
  23. 410 then: 24 else: 386 dice == 0 ? 100 : dice
  24. end
  25. dice =
  26. 205 then: 103 if bonus >= 0
  27. 103 dice_list.min
  28. else: 102 else
  29. 102 dice_list.max
  30. end
  31. 205 return dice, dice_list
  32. end
  33. end
  34. end
  35. end
  36. end

lib/bcdice/game_system/cyberpunk_red/tables.rb

100.0% lines covered

100.0% branches covered

84 relevant lines. 84 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class CyberpunkRed < Base
  5. 1 class ScreamSheetRandomizerTable
  6. 1 def initialize(locale:, type_table:, a_table:, of_table:, b_table:, c_table:)
  7. 2 @locale = locale
  8. 2 @type_table = type_table
  9. 2 @a_table = a_table
  10. 2 @of_table = of_table
  11. 2 @b_table = b_table
  12. 2 @c_table = c_table
  13. end
  14. 1 def roll(randomizer)
  15. 4 result = ""
  16. 4 dice = randomizer.roll_once(6)
  17. 4 scs_type = @type_table.choice(dice)
  18. 4 result += "#{scs_type}#{I18n.translate('CyberpunkRed.news', locale: @locale, raise: true)} 『"
  19. 4 dice = randomizer.roll_once(10)
  20. 4 scs_val_a = @a_table.choice(dice).body
  21. 4 result += scs_val_a
  22. 4 dice = randomizer.roll_once(6)
  23. 4 scs_val_of = @of_table.choice(dice).body
  24. 4 result += scs_val_of
  25. 4 dice = randomizer.roll_once(10)
  26. 4 scs_val_a = @a_table.choice(dice).body
  27. 4 result += scs_val_a
  28. 4 dice = randomizer.roll_once(6)
  29. 4 scs_val_of = @of_table.choice(dice).body
  30. 4 result += scs_val_of
  31. 4 dice = randomizer.roll_once(10)
  32. 4 scs_val_b = @b_table.choice(dice).body
  33. 4 result += scs_val_b
  34. 4 dice = randomizer.roll_once(10)
  35. 4 scs_val_c = @c_table.choice(dice).body
  36. 4 result += scs_val_c
  37. 4 result += "』"
  38. 4 return result
  39. end
  40. end
  41. 1 class ShopPeopleTable
  42. 1 def initialize(locale:, staff_table:, people_a_table:, people_b_table:)
  43. 2 @locale = locale
  44. 2 @staff_table = staff_table
  45. 2 @people_a_table = people_a_table
  46. 2 @people_b_table = people_b_table
  47. end
  48. 1 def roll(randomizer)
  49. 4 result = I18n.translate("CyberpunkRed.ShopPeopleTableText.intro", locale: @locale, raise: true)
  50. 4 dice = randomizer.roll_once(6)
  51. 4 staff = @staff_table.choice(dice).body
  52. 4 staff = staff[0..-2]
  53. 4 result += staff
  54. 4 result += I18n.translate("CyberpunkRed.ShopPeopleTableText.shop_staff", locale: @locale, raise: true)
  55. 4 dice = randomizer.roll_once(6)
  56. 4 people = @people_a_table.choice(dice).body
  57. 4 people = people[0..-2]
  58. 4 result += people
  59. 4 result += I18n.translate("CyberpunkRed.ShopPeopleTableText.people_a", locale: @locale, raise: true)
  60. 4 dice = randomizer.roll_once(6)
  61. 4 people = @people_b_table.choice(dice).body
  62. 4 people = people[0..-2]
  63. 4 result += people
  64. 4 result += I18n.translate("CyberpunkRed.ShopPeopleTableText.people_b", locale: @locale, raise: true)
  65. 4 result += I18n.translate("CyberpunkRed.ShopPeopleTableText.outro", locale: @locale, raise: true)
  66. 4 return result
  67. end
  68. end
  69. 1 class << self
  70. 1 private
  71. 1 def translate_tables(locale)
  72. 2 nigit_market_type_table = DiceTable::Table.from_i18n("CyberpunkRed.NightMarketTypeTable", locale)
  73. 2 night_market_foods_table = DiceTable::RangeTable.from_i18n("CyberpunkRed.NightMarketFoodsTable", locale)
  74. 2 night_market_mechanic_table = DiceTable::RangeTable.from_i18n("CyberpunkRed.NightMarketMechanicTable", locale)
  75. 2 night_market_weapons_table = DiceTable::RangeTable.from_i18n("CyberpunkRed.NightMarketWeaponsTable", locale)
  76. 2 night_market_cyberware_table = DiceTable::RangeTable.from_i18n("CyberpunkRed.NightMarketCyberwareTable", locale)
  77. 2 night_market_fashion_table = DiceTable::RangeTable.from_i18n("CyberpunkRed.NightMarketFashionTable", locale)
  78. 2 night_market_suvival_table = DiceTable::RangeTable.from_i18n("CyberpunkRed.NightMarketSuvivalTable", locale)
  79. 2 scream_sheet_type_table = DiceTable::Table.from_i18n("CyberpunkRed.ScreamSheetTypeTable", locale)
  80. 2 scream_sheet_a_table = DiceTable::Table.from_i18n("CyberpunkRed.ScreamSheetATable", locale)
  81. 2 scream_sheet_b_table = DiceTable::Table.from_i18n("CyberpunkRed.ScreamSheetBTable", locale)
  82. 2 scream_sheet_c_table = DiceTable::Table.from_i18n("CyberpunkRed.ScreamSheetCTable", locale)
  83. 2 scream_sheet_of_table = DiceTable::Table.from_i18n("CyberpunkRed.ScreamSheetOfTable", locale)
  84. 2 vending_machine_type_table = DiceTable::RangeTable.from_i18n("CyberpunkRed.VendingMachineTypeTable", locale)
  85. 2 vending_machine_food_table = DiceTable::Table.from_i18n("CyberpunkRed.VendingMachineFoodTable", locale)
  86. 2 vending_machine_fashion_table = DiceTable::Table.from_i18n("CyberpunkRed.VendingMachineFashionTable", locale)
  87. 2 vending_machine_strange_table = DiceTable::Table.from_i18n("CyberpunkRed.VendingMachineStrangeTable", locale)
  88. 2 shop_staff_table = DiceTable::Table.from_i18n("CyberpunkRed.ShopStaffTable", locale)
  89. 2 shop_people_a_table = DiceTable::Table.from_i18n("CyberpunkRed.ShopPeopleATable", locale)
  90. 2 shop_people_b_table = DiceTable::Table.from_i18n("CyberpunkRed.ShopPeopleBTable", locale)
  91. return {
  92. 2 "FFD" => DiceTable::Table.from_i18n("CyberpunkRed.FrameFatalDamageTable", locale),
  93. "HFD" => DiceTable::Table.from_i18n("CyberpunkRed.HeadFatalDamageTable", locale),
  94. "NCDT" => DiceTable::RangeTable.from_i18n("CyberpunkRed.NightCityDaytimeEncounterTable", locale),
  95. "NCMT" => DiceTable::RangeTable.from_i18n("CyberpunkRed.NightCityMidnightEncounterTable", locale),
  96. "NMCT" => nigit_market_type_table,
  97. "NMCFO" => night_market_foods_table,
  98. "NMCME" => night_market_mechanic_table,
  99. "NMCWE" => night_market_weapons_table,
  100. "NMCCY" => night_market_cyberware_table,
  101. "NMCFA" => night_market_fashion_table,
  102. "NMCSU" => night_market_suvival_table,
  103. "SCST" => scream_sheet_type_table,
  104. "SCSA" => scream_sheet_a_table,
  105. "SCSB" => scream_sheet_b_table,
  106. "SCSC" => scream_sheet_c_table,
  107. "SCSR" => ScreamSheetRandomizerTable.new(
  108. locale: locale,
  109. type_table: scream_sheet_type_table,
  110. a_table: scream_sheet_a_table,
  111. b_table: scream_sheet_b_table,
  112. c_table: scream_sheet_c_table,
  113. of_table: scream_sheet_of_table
  114. ).freeze,
  115. "VMCT" => vending_machine_type_table,
  116. "VMCE" => vending_machine_food_table,
  117. "VMCF" => vending_machine_fashion_table,
  118. "VMCS" => vending_machine_strange_table,
  119. "VMCR" => DiceTable::ChainTable.new(
  120. I18n.translate("CyberpunkRed.VendingMachineTable.name", locale: locale, raise: true),
  121. "1D6",
  122. [
  123. vending_machine_food_table,
  124. vending_machine_food_table,
  125. vending_machine_food_table,
  126. vending_machine_fashion_table,
  127. vending_machine_fashion_table,
  128. vending_machine_strange_table
  129. ]
  130. ),
  131. "STOREA" => shop_staff_table,
  132. "STOREB" => shop_people_a_table,
  133. "STOREC" => shop_people_b_table,
  134. "STORE" => ShopPeopleTable.new(
  135. locale: locale,
  136. staff_table: shop_staff_table,
  137. people_a_table: shop_people_a_table,
  138. people_b_table: shop_people_b_table
  139. ).freeze
  140. }.freeze
  141. end
  142. end
  143. end
  144. end
  145. end

lib/bcdice/game_system/filled_with/cook_tables.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/dice_table/range_table"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class FilledWith
  6. # マジカルクッキング表
  7. #
  8. # 別の表に飛ぶ場合は、遅延評価のためにlambdaでジャンプ先の表を括る。
  9. COOK_TABLES = {
  10. 1 1 => DiceTable::RangeTable.new(
  11. "マジカルクッキング(Lv 1)",
  12. "1D6",
  13. [
  14. [1, "おべんとミートボール"],
  15. [2, "パリパリ小魚"],
  16. [3, "キャロットタルト"],
  17. [4, "おにぎり"],
  18. 1 [5..6, lambda { COOK_TABLES[2] }],
  19. ]
  20. ).freeze,
  21. 2 => DiceTable::RangeTable.new(
  22. "マジカルクッキング(Lv 2)",
  23. "1D6",
  24. [
  25. [1, "カリカリミミズ肉"],
  26. [2, "竹つきチクワ"],
  27. [3, "トロピカルジュース"],
  28. [4, "イナリ寿司"],
  29. 1 [5..6, lambda { COOK_TABLES[3] }],
  30. ]
  31. ).freeze,
  32. 3 => DiceTable::RangeTable.new(
  33. "マジカルクッキング(Lv 3)",
  34. "1D6",
  35. [
  36. [1, "ホットミートパイ"],
  37. [2, "魔界魚の目玉"],
  38. [3, "パンプキンプリン"],
  39. [4, "スタミナ丼"],
  40. 1 [5..6, lambda { COOK_TABLES[4] }],
  41. ]
  42. ).freeze,
  43. 4 => DiceTable::RangeTable.new(
  44. "マジカルクッキング(Lv 4)",
  45. "1D6",
  46. [
  47. [1, "ジャンボ串焼き"],
  48. [2, "シルヴァまっしぐら"],
  49. [3, "フラウアイスクリーム"],
  50. [4, "ピクニックランチ"],
  51. 1 [5..6, lambda { COOK_TABLES[5] }],
  52. ]
  53. ).freeze,
  54. 5 => DiceTable::RangeTable.new(
  55. "マジカルクッキング(Lv 5)",
  56. "1D6",
  57. [
  58. [1, "グラント風香草焼き"],
  59. [2, "エドマエスシ"],
  60. [3, "スターフルーツパフェ"],
  61. [4, "具沢山本格カレー"],
  62. 2 [5..6, lambda { COOK_TABLES[6] }],
  63. ]
  64. ).freeze,
  65. 6 => DiceTable::RangeTable.new(
  66. "マジカルクッキング(Lv 6)",
  67. "1D6",
  68. [
  69. [1, "ドラゴンステーキ"],
  70. [2, "刺身盛り合わせ"],
  71. [3, "エデンのアップルパイ"],
  72. [4, "フォートレス炒飯"],
  73. 2 [5..6, lambda { COOK_TABLES[7] }],
  74. ]
  75. ).freeze,
  76. 7 => DiceTable::RangeTable.new(
  77. "マジカルクッキング(Lv 7)",
  78. "1D6",
  79. [
  80. [1, "マツザカスペシャル"],
  81. [2, "オオトロスシ"],
  82. [3, "スノーホワイトボンブ"],
  83. [4, "よもつへぐい"],
  84. 2 [5..6, lambda { COOK_TABLES[8] }],
  85. ]
  86. ).freeze,
  87. 8 => DiceTable::RangeTable.new(
  88. "マジカルクッキング(Lv 8)",
  89. "1D6",
  90. [
  91. [1, "超特大マンガ肉"],
  92. [2, "特上うな丼"],
  93. [3, "魔将樹のかき氷"],
  94. [4, "ヘブンズランチ"],
  95. 1 [5..6, lambda { COOK_TABLES[9] }],
  96. ]
  97. ).freeze,
  98. 9 => DiceTable::RangeTable.new(
  99. "マジカルクッキング(Lv 9)",
  100. "1D6",
  101. [
  102. [1..3, "世界樹のサラダ"],
  103. [4..6, "黄金のラダマン鍋"],
  104. ]
  105. ).freeze,
  106. }.freeze
  107. end
  108. end
  109. end

lib/bcdice/game_system/filled_with/enemy_data_tables.rb

92.86% lines covered

50.0% branches covered

14 relevant lines. 13 lines covered and 1 lines missed.
2 total branches, 1 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class FilledWith < Base
  5. # 夢幻の迷宮エネミーデータ表
  6. 1 def fetch_enemy_data(command)
  7. 6 m = /^RED([ENHLX])(256|265|465|665|666|[1-6]4[1-6])$/.match(command)
  8. 6 else: 6 then: 0 unless m
  9. return nil
  10. end
  11. 6 difficulty = Difficulty.new(m[1])
  12. 6 key = m[2]
  13. 6 area_name = AREA_LIST[key[0].to_i - 1]
  14. 6 chosen = ENEMY_DATA[key][difficulty.index]
  15. 6 return "エネミーデータ表(#{key}):#{area_name}<#{difficulty.name}>:#{chosen}"
  16. end
  17. 1 AREA_LIST = [
  18. "洞窟",
  19. "遺跡",
  20. "山岳",
  21. "水辺",
  22. "森林",
  23. "墓場",
  24. ].freeze
  25. ENEMY_DATA = {
  26. 1 "141" => [
  27. "キャンディークラウン(CL40)1匹",
  28. "キャンディクラウン(CL40)「1D-3」匹(最低1匹)",
  29. "キャンディークラウン「1D-2」匹(最低1匹)出目が6だった場合ゴールデンクラウン(CL177)1匹",
  30. "ゴールデンクラウン(CL177)とエンカウント",
  31. "キャンディークラウン(CL40/オリジン)1匹"
  32. ],
  33. "142" => [
  34. "ベルセルク(CL7)3匹",
  35. "ベルセルク(CL7)3匹(〔命中〕+4、〔HP〕+30、〔FP〕+10、あらゆる致傷力+20)",
  36. "ベルセルク(CL7)3匹(〔命中〕+8、〔HP〕+60、〔FP〕+20、あらゆる致傷力+40)",
  37. "ベルセルク(CL7)3匹(〔命中〕+16、〔HP〕+120、〔FP〕+40、あらゆる致傷力+80)",
  38. "ベルセルク(CL7/オリジン)3匹(〔HP〕+500、あらゆる致傷力+100)"
  39. ],
  40. "143" => [
  41. "ガーゴイル(CL10)2匹",
  42. "ガーゴイル(CL10)2匹(〔命中〕+4、〔HP〕+20、〔FP〕+10、あらゆる致傷力と防護点+20)",
  43. "ガーゴイル(CL10)2匹(〔命中〕+8、〔HP〕+40、〔FP〕+20、あらゆる致傷力と防護点+40)",
  44. "ザッハーク(CL39)3匹",
  45. "ガーゴイル(CL10/オリジン)2匹(〔HP〕+500、あらゆる致傷力と防護点+100)"
  46. ],
  47. "144" => [
  48. "デビルホイール(CL18)1匹",
  49. "デビルホイール(CL18)1匹、あらゆる致傷力+20",
  50. "デビルホイール(CL18)1匹、あらゆる致傷力+40",
  51. "ムスペルヘイムの獣(CL65)、あらゆる防護点+20",
  52. "デビルホイール(CL18/オリジン)1匹(〔HP〕+1000、あらゆる致傷力+100)"
  53. ],
  54. "145" => [
  55. "ヘルハウンド(CL12)1匹、インプ(CL3)2匹",
  56. "フェニックス(CL25)2匹",
  57. "火龍ヘルブレイザー(CL50)1匹、ケルベロス(CL33)1匹",
  58. "煉獄龍バーガトリ(CL100)1匹",
  59. "ヘルハウンド(CL12/オリジン)1匹、インプ(CL3/オリジン)2匹(〔HP〕+500、あらゆる致傷力+100)"
  60. ],
  61. "146" => [
  62. "アイスメイデン(CL10)1匹、アイスリザード(CL7)2匹",
  63. "クリスタルビースト(CL25)2匹",
  64. "氷河龍グレイシャル(CL65)1匹",
  65. "冥界龍コキュートス(CL110)1匹",
  66. "アイスメイデン(CL10/オリジン)1匹、アイスリザード(CL7/オリジン)2匹(〔HP〕+500、あらゆる致傷力+100)"
  67. ],
  68. "241" => [
  69. "スケルトン(CL3)、アルテミス(CL8)、スターゲイザー(CL10)、ヤシャ(CL10)、ヘルハウンド(CL12)、ゴーレム(CL13)",
  70. "ナイトスケルトン(CL12)、カラクリフラウ弐式(CL16)、コスモロジスト(CL20)、クリスタルビースト(CL25)、ミスリルゴーレム(CL27)",
  71. "コガラシ(CL27)、アダマンゴーレム(CL45)、アシュラ(CL48)、火龍ヘルブレイザー(CL50)、氷龍グレイシャル(CL65)",
  72. "ロックダンサー(CL39)、デスサジタリー(CL45)、コンゴウ(CL60)、カラクリヒメショーグン(CL75)、フェンリル(CL85)、ゴールデンクラウン(CL177)\nゴールデンクラウンが最後に残り【逃走】した場合ドロップ品は入手できない",
  73. "スケルトン(CL3/オリジン)、アルテミス(CL8/オリジン)、スターゲイザー(CL10/オリジン)、ヤシャ(CL10/オリジン)、ヘルハウンド(CL12/オリジン)、ゴーレム(CL13/オリジン)(〔HP〕+500、あらゆる致傷力+100)"
  74. ],
  75. "242" => [
  76. "アルテミス(CL8)3匹",
  77. "アルテミス(CL8)3匹(〔命中〕+4、〔HP〕+30、〔FP〕+20、あらゆる致傷力+20)",
  78. "アルテミス(CL8)3匹(〔命中〕+8、〔HP〕+60、〔FP〕+30、あらゆる致傷力+40)",
  79. "アルテミス(CL8)3匹(〔命中〕+16、〔HP〕+120、〔FP〕+40、あらゆる致傷力+80)",
  80. "アルテミス(CL8/オリジン)3匹(〔HP〕+500、あらゆる致傷力+100)"
  81. ],
  82. "243" => [
  83. "スターゲイザー(CL10)2匹",
  84. "コスモロジスト(CL20)2匹",
  85. "コスモロジスト(CL20)4匹",
  86. "デスサジタリー(CL45)2匹",
  87. "スターゲイザー(CL10/オリジン)2匹(〔HP〕+500、あらゆる致傷力+100)"
  88. ],
  89. "244" => [
  90. "ヤシャ(CL10)1匹、スケルトン(CL3)3匹",
  91. "ヤシャ(CL10)3匹(〔命中〕+4、〔HP〕+30、〔FP〕+10、あらゆる致傷力+15)",
  92. "アシュラ(CL48)2匹",
  93. "コンゴウ(CL60)2匹",
  94. "ヤシャ(CL10/オリジン)1匹、スケルトン(CL3/オリジン)3匹(〔HP〕+500、あらゆる致傷力+100)"
  95. ],
  96. "245" => [
  97. "ヘルハウンド(CL12)2匹",
  98. "クリスタルビースト(CL25)2匹",
  99. "火龍ヘルブレイザー(CL50)1匹、氷河龍グレイシャル(CL65)",
  100. "『単眼の巨神』アイングロース(CL100/ネームド)",
  101. "ヘルハウンド(CL12/オリジン)2匹(〔HP〕+500、あらゆる致傷力+100)"
  102. ],
  103. "246" => [
  104. "ゴーレム(CL13)1匹",
  105. "ミスリルゴーレム(CL27)1匹",
  106. "アダマンゴーレム(CL45)1匹",
  107. "カラクリヒメショーグン(CL75)1匹",
  108. "ゴーレム(CL13/オリジン)1匹(〔HP〕+1000、あらゆる致傷力+100)"
  109. ],
  110. "341" => [
  111. "アイアンプリチン(CL5)5匹",
  112. "アイアンプリチン(CL5)5匹(〔命中〕+4、〔HP〕+30、〔FP〕+10)",
  113. "アイアンプリチン(CL5)5匹(〔命中〕+8、〔HP〕+60、〔FP〕+20)",
  114. "アイアンプリチン(CL5)5匹(〔命中〕+16、〔HP〕+120、〔FP〕+40)",
  115. "アイアンプリチン(CL5/オリジン)5匹(〔HP〕+300、あらゆる致傷力+100)"
  116. ],
  117. "342" => [
  118. "ウイングスレイブ(CL4)5匹",
  119. "ウイングスレイブ(CL4)5匹(〔命中〕+4、〔HP〕+30、〔FP〕+10、あらゆる致傷力+20)",
  120. "ガルーダ(CL40)2匹",
  121. "栄光の天使(CL60)2匹",
  122. "ウイングスレイブ(CL4/オリジン)5匹(〔HP〕+300、あらゆる致傷力+100)"
  123. ],
  124. "343" => [
  125. "ブラックナイト(CL10)1匹、ソルジャー(CL4)3匹",
  126. "デュラハン(CL22)1匹、ブラックナイト(CL10)2匹",
  127. "サーバントマスター(CL35)1匹、デュラハン(CL22)2匹",
  128. "ジェネラル(CL55)1匹、サーバントマスター(CL35)2匹",
  129. "ブラックナイト(CL10/オリジン)1匹、ソルジャー(CL4/オリジン)3匹(〔HP〕+500、あらゆる致傷力+100)"
  130. ],
  131. "344" => [
  132. "ソルジャーアント(CL8)2匹",
  133. "ソルジャーアント(CL8)2匹(〔命中〕+4、〔HP〕+30、〔FP〕+10、あらゆる致傷力+20)",
  134. "インペリアルアント(CL30)2匹",
  135. "『女王キノコ』アカシックツリー(CL50/ネームド)1匹、インペリアルアント(CL30)2匹",
  136. "ソルジャーアント(CL8/オリジン)2匹(〔HP〕+500、あらゆる致傷力+100)"
  137. ],
  138. "345" => [
  139. "カボチャの魔女(CL8)2匹",
  140. "カボチャの魔女(CL8)2匹(〔命中〕+4、〔HP〕+30、〔FP〕+10、あらゆる致傷力+20)",
  141. "カボチャの大魔女(CL35)2匹",
  142. "堕落の黒天使(CL60)2匹",
  143. "カボチャの魔女(CL8/オリジン)2匹(〔HP〕+500、あらゆる致傷力+100)"
  144. ],
  145. "346" => [
  146. "フェニックス(CL25)2匹",
  147. "フェニックス(CL25)2匹(〔命中〕+4、〔HP〕+40、〔FP〕+10、あらゆる致傷力+30)",
  148. "フェニックス(CL25)2匹(〔命中〕+8、〔HP〕+80、〔FP〕+20、あらゆる致傷力+60)",
  149. "煉獄フェニックス(CL85)2匹",
  150. "フェニックス(CL25/オリジン)2匹(〔HP〕+1000、あらゆる致傷力+200)"
  151. ],
  152. "441" => [
  153. "フロストクラブ(CL6)2匹",
  154. "フロストクラブ(CL6)3匹",
  155. "『氷海の主』ギガントキャンサー(CL20/ネームド)",
  156. "『氷海の主』ギガントキャンサー(CL20/ネームド)、フロストクラブ(CL6)3匹",
  157. "フロストクラブ(CL6/オリジン)2匹(〔HP〕+500、あらゆる致傷力+100)"
  158. ],
  159. "442" => [
  160. "アシガル(CL4)3匹",
  161. "ハタモト(CL10)3匹",
  162. "ヒトキリ(CL33)2匹",
  163. "スカーレス(CL38)3匹",
  164. "アシガル(CL4/オリジン)3匹(〔HP〕+500、あらゆる致傷力+100)"
  165. ],
  166. "443" => [
  167. "アンブッシュマン(CL5)3匹",
  168. "アンブッシュマン(CL5)3匹(〔命中〕+4、〔HP〕+20、〔FP〕+10、あらゆる致傷力+10)",
  169. "シャドウストーカー(CL35)2匹",
  170. "シャドウストーカー(CL35)3匹",
  171. "アンブッシュマン(CL5/オリジン)3匹(〔HP〕+500、あらゆる致傷力+100)"
  172. ],
  173. "444" => [
  174. "アップルドール(CL12)2匹",
  175. "アップルドール(CL12)2匹、ポイズンリリー(CL7)2匹",
  176. "テラードール(CL30)2匹",
  177. "テラードール(CL30)2匹、バリアリーフ(CL27)2匹",
  178. "アップルドール(CL12/オリジン)2匹(〔HP〕+500、あらゆる致傷力+100)"
  179. ],
  180. "445" => [
  181. "ナイトライダー(CL15)1匹",
  182. "ナイトライダー(CL15)2匹",
  183. "ジェネラル(CL55)1匹",
  184. "ジェネラル(CL55)2匹",
  185. "ナイトライダー(CL15/オリジン)1匹(〔HP〕+800、あらゆる致傷力+100)"
  186. ],
  187. "446" => [
  188. "ジェルスケルトン(CL10)1匹",
  189. "ジェルスケルトン(CL10)1匹(〔命中〕+4、〔FP〕+10、あらゆる致傷力+20)",
  190. "ジェルスケルトン(CL10)1匹(〔命中〕+8、〔FP〕+20、あらゆる致傷力+40)",
  191. "ジェルスケルトン(CL10)1匹(〔命中〕+12、〔FP〕+40、あらゆる致傷力+80)",
  192. "ジェルスケルトン(CL10/オリジン)1匹(〔HP〕+1500、あらゆる致傷力+200)"
  193. ],
  194. "541" => [
  195. "スナッチャー(CL4)3匹",
  196. "ゴールデンビースト(CL10)3匹",
  197. "ヨウコ(CL30)2匹",
  198. "イビルオーメン(CL42)2匹",
  199. "スナッチャー(CL4/オリジン)3匹(〔HP〕+500、あらゆる致傷力+100)"
  200. ],
  201. "542" => [
  202. "スターゲイザー(CL10)1匹、オーク(CL3)3匹",
  203. "スターゲイザー(CL10)1匹、ヘルハウンド(CL12)2匹",
  204. "コスモロジスト(CL20)1匹、ケルベロス(CL33)1匹",
  205. "サーバントマスター(CL35)1匹、ケルベロス(CL33)2匹",
  206. "スターゲイザー(CL10/オリジン)1匹、オーク(CL3/オリジン)3匹(〔HP〕+500、あらゆる致傷力+100)"
  207. ],
  208. "543" => [
  209. "オウルセージ(CL5)1匹、インプ(CL3)3匹。指定エネミー:オウルセージ",
  210. "オウルセージ(CL5)3匹。指定エネミー:オウルセージ",
  211. "オウルコマンダー(CL18)1匹、キメラ(CL15)2匹。指定エネミー:オウルコマンダー",
  212. "オウルコマンダー(CL18)2匹、キメラグレート(CL60)1匹。指定エネミー:オウルコマンダー",
  213. "オウルセージ(CL/オリジン5)1匹、インプ(CL3/オリジン)3匹(〔HP〕+500、あらゆる致傷力+100)。指定エネミー:オウルセージ"
  214. ],
  215. "544" => [
  216. "グリーンアクトレス(CL22)1匹",
  217. "魔将樹の騎士(CL40)1匹",
  218. "魔将樹の番人(CL80)1匹",
  219. "『魔将樹の剣姫』ロジエモール(CL120/ネームド)1匹",
  220. "グリーンアクトレス(CL22/オリジン)1匹(〔HP〕+200、あらゆる致傷力+200、分類「ネームド」と【始原の力】を追加)"
  221. ],
  222. "545" => [
  223. "ポイズンリリー(CL7)1匹、リリーの尖兵(CL5)1匹",
  224. "ポイズンリリー(CL7)1匹、リリーの尖兵(CL5)1匹(〔命中〕+4、〔HP〕+30、〔FP〕+10、あらゆる致傷力+20)",
  225. "バリアリーフ(CL27)1匹、リリーの尖兵(CL5)1匹(〔命中〕+8、〔HP〕+60、〔FP〕+20、あらゆる致傷力+40)",
  226. "『密林の女王』クイーンリリー(CL70/ネームド)1匹、リリーの尖兵(CL5)1匹(〔命中〕+16、〔HP〕+120、〔FP〕+40、あらゆる致傷力+80)",
  227. "ポイズンリリー(CL7/オリジン)1匹、リリーの尖兵(CL5/オリジン)1匹(〔HP〕+800、あらゆる致傷力+100)"
  228. ],
  229. "546" => [
  230. "ブラックナイト(CL10)1匹、ソルジャー(CL4)3匹",
  231. "ヴァルキリー(CL20)1匹、ブラックナイト(CL10)2匹",
  232. "フレイヤ(CL45)1匹、ヴァルキリー(CL20)2匹",
  233. "ジェネラル(CL55)1匹、フレイヤ(CL45)2匹",
  234. "ブラックナイト(CL10/オリジン)1匹、ソルジャー(CL4/オリジン)3匹(〔HP〕+500、あらゆる致傷力+100)"
  235. ],
  236. "641" => [
  237. "ヤコ(CL6)3匹(【狐の送り火】のデータを「疲労:なし」に変更)",
  238. "ヨウコ(CL30)1匹(【狐の送り火】のデータを「疲労:なし」に変更)",
  239. "ヨウコ(CL30)3匹(【狐の送り火】のデータを「疲労:なし」に変更)",
  240. "タタリドラゴン(CL60/ネームド)1匹(【狐の送り火】のデータを「疲労:なし」に変更)",
  241. "ヤコ(CL6/オリジン)3匹((〔HP〕+500、あらゆる致傷力+100、【狐の送り火】のデータを「疲労:なし」に変更)"
  242. ],
  243. "642" => [
  244. "スケルトン(CL3)4匹",
  245. "ナイトスケルトン(CL12)3匹",
  246. "ヒトキリ(CL33)2匹(「分類:アンデッド」を追加)",
  247. "堕ちた黒龍(CL48)2匹",
  248. "スケルトン(CL3/オリジン)4匹(〔HP〕+500、あらゆる致傷力+200)"
  249. ],
  250. "643" => [
  251. "ポイズンリリー(CL7)1匹(【華劇:リリーオブザバレー】使用済み)、ファントム(CL5)2匹",
  252. "ポイズンリリー(CL7)1匹(【華劇:リリーオブザバレー】使用済み)、ゴースト(CL10)3匹",
  253. "グリーンアクトレス(CL22)1匹(【華劇:フォレストステップ】使用済み)、デュラハン(CL22)2匹",
  254. "グリーンアクトレス(CL22)1匹(【華劇:フォレストステップ】使用済み)、カラクリヒメショーグン(CL75)1匹",
  255. "ポイズンリリー(CL7/オリジン)1匹(【華劇:リリーオブザバレー】使用済み)、ファントム(CL5)2匹(〔HP〕+500、あらゆる致傷力+100)"
  256. ],
  257. "644" => [
  258. "君たちの冒険はここで終了だ。",
  259. "君たちの冒険はここで終了だ。",
  260. "君たちの冒険はここで終了だ。",
  261. "第二魔将『葬送者』グレイヴディガー(CL200/魔将)1匹、『ディガー様親衛隊長』フュネライユ(CL66/ネームド)1匹、『トラップマスター』アンテルモン(CL65/ネームド)1匹",
  262. "[現在エネミー未実装の為振り直ししてください]",
  263. ],
  264. "645" => [
  265. "ゴースト(CL10)1匹(通常ドロップ「1000GP」)、ソルジャー(CL4)2匹",
  266. "ゴースト(CL10)1匹(通常ドロップ「2000GP」)、ハタモト(CL10)3匹",
  267. "リッチ(CL44)1匹(通常ドロップ「4000GP」)、ミスリルゴーレム(CL27)1匹",
  268. "エルダーリッチ(CL55)1匹(通常ドロップ「8000GP」)、アダマンゴーレム(CL45)1匹",
  269. "ゴースト(CL10/オリジン)1匹(通常ドロップ「1000GP」)、ソルジャー(CL4/オリジン)2匹(〔HP〕+500、あらゆる致傷力+100)"
  270. ],
  271. "646" => [
  272. "ボーンスネーク(CL20)1匹",
  273. "ボーンスネーク(CL20)2匹",
  274. "ラダマンティスの蛇(CL50)1匹",
  275. "ラダマンティスの蛇(CL50)1匹(ネームド仕様[HP4倍、【ネームドエネミー】習得])",
  276. "ボーンスネーク(CL20/オリジン)1匹(〔HP〕+1500、あらゆる致傷力+200)"
  277. ],
  278. "256" => [
  279. "ボーンスネーク(CL50)1匹",
  280. "ラダマンティスの蛇(CL50)1匹",
  281. "銀河龍ラクテア/ドラゴン形態(CL90)1匹",
  282. "『三つ首の災厄』トライディザスター(CL100/ネームド)1匹",
  283. "ボーンスネーク(CL50/オリジン)1匹(〔HP〕+2000、あらゆる致傷力+200)"
  284. ],
  285. "265" => [
  286. "キャンディークラウン(CL40)「1D6」匹",
  287. "キャンディークラウン(CL40)「1D6+1」匹",
  288. "キャンディークラウン(CL40)「1D6」匹、ゴールデンクラウン(CL177)1匹",
  289. "キャンディークラウン(CL40)「1D6」匹、ゴールデンクラウン(CL177)2匹",
  290. "キャンディークラウン(CL40/オリジン)「1D6」匹",
  291. ],
  292. "465" => [
  293. "リビングデッド(CL5)3匹",
  294. "ゴースト(CL10)3匹",
  295. "デュラハン(CL22)3匹",
  296. "リッチ(CL44)3匹",
  297. "リビングデッド(CL5/オリジン)3匹(〔HP〕+500、あらゆる致傷力+100)"
  298. ],
  299. "665" => [
  300. "カロン(CL12)2匹",
  301. "カロンキャプテン(CL25)2匹",
  302. "リッチ(CL44)2匹",
  303. "エルダーリッチ(CL55)2匹(〔HP〕+10)",
  304. "カロンキャプテン(CL25/オリジン)2匹"
  305. ],
  306. "666" => [
  307. "『漆黒の戦鬼』ブラックナイト(CL10/ネームド)1匹",
  308. "『漆黒の戦鬼』ブラックナイト(CL10/ネームド)1匹(〔命中〕+4、あらゆる致傷力+20、〔HP〕+200)",
  309. "『白銀の猛将』ジェネラル(CL55/ネームド)1匹",
  310. "『白銀の猛将』ジェネラル(CL55/ネームド)1匹(〔命中〕+4、あらゆる致傷力+20、〔HP〕+500)",
  311. "[現在エネミー未実装の為振り直ししてください]"
  312. ],
  313. }.freeze
  314. end
  315. end
  316. end

lib/bcdice/game_system/filled_with/event_tables.rb

100.0% lines covered

100.0% branches covered

21 relevant lines. 21 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class FilledWith
  5. 1 class EventTable
  6. 1 def initialize(area_name, area_id, rows)
  7. 6 @area_name = area_name
  8. 6 @area_id = area_id
  9. 6 @rows = rows
  10. end
  11. 1 def roll(randomizer, difficality, type: nil)
  12. 7 tens = type || randomizer.roll_once(6)
  13. 7 ones = randomizer.roll_once(6)
  14. 7 value = tens * 10 + ones
  15. 7 chosen = @rows[value]
  16. 7 "ランダムイベント表(#{@area_id}#{value}):#{@area_name}<#{difficality.name}>:#{chosen.format(difficality)}"
  17. end
  18. end
  19. 1 cave = EventTable.new(
  20. "洞窟",
  21. 1,
  22. {
  23. 11 => Row.new("回復の泉。PC全員の〔HP〕〔FP〕が完全に回復する。「★死亡」以外のあらゆるBSも回復する。"),
  24. 12 => Row.new("淡い光を放つ鉱石に包まれた部屋に出る。Ftが%s点回復する。", [1, 2, 3, 4, 1]),
  25. 13 => Row.new("天井が開いていて植物の育っている洞窟内庭園。[知力-%s]判定に成功すると、力の沸く木の実を見つけてPC全員の〔HP〕〔FP〕を%s点回復できる。有効:「自然と生きる」【賢人の知恵】", [3, 6, 9, 12, 15], [20, 30, 40, 50, 100]),
  26. 14 => Row.new("「きのこっきのこっげんきでろ~♪」洞窟内で栽培できる特殊なキノコを栽培する、キノコのフラウに出会う。100GP支払うことでキノコを1つ譲ってもらうことができ、〔HP〕が全回復してシナリオ終了まで〔HP〕の最大値に+%sのボーナスを得る。", [10, 15, 20, 25, 30]),
  27. 15 => Row.new("ギア技術を用いた強力な懐中電灯のおいてある休憩室。迷宮を出るまでPC全員に有利な特異点「猫の目」があるものとして扱う。迷宮を出ると懐中電灯は寿命が来たのか壊れてしまう。"),
  28. 16 => Row.new("不思議な光を放つ水が湧いている。PCの〔HP〕〔FP〕のいずれかが減少している場合、このイベントは拒否できない。また全快でも不利な特異点「好奇心は猫を殺す」を持つPCは飲みにいこうとする。飲んだキャラクターは1D6を振り、以下の様な効果が発生する。
  29. ----------
  30. 1:〔HP〕〔FP〕と「★死亡」以外のBS全回復
  31. 2:シナリオ終了まで不利な特異点が全て消滅する
  32. 3:シナリオ終了まで「真実を知る者」「お金持ち」などのキャラクターの地位や立場に関連するものを除いた有利な特異点が全て消滅する
  33. 4:〔HP〕が1点になってしまう。〔HP〕が0以下の場合は〔HP〕〔FP〕が全回復
  34. 5:シナリオ終了まで余分な獣っぽい耳や尻尾が生える。既に生えているキャラクターはそれが大きくなる。聴覚に関する[感覚]判定+4。
  35. 6:あいやー!それ呪いの泉アルよ!シナリオ終了まで性別が男女入れ替わる。ロールプレイが面白かった場合、シナリオ終了時に「アタッチメント割引券」を与えても良い"),
  36. 21 => Row.new("財宝ランク%sの宝箱を発見する。カギやトラップはかかっていない。行動を消費することで開けることができる。", [0, 2, 4, 6, 8]),
  37. 22 => Row.new("財宝ランク%sの宝箱を発見する。難易度%sのカギがかかっている。行動を消費して[感覚-%s]判定でカギを解除して開けることができる。有効:【盗賊の心得】【ロックスミス】", [1, 3, 5, 7, 9], [3, 6, 9, 12, 20], [3, 6, 9, 12, 20]),
  38. 23 => Row.new("財宝ランク%sの宝箱を発見する。難易度%sのトラップがかかっている。行動を消費して[感覚-%s]判定でトラップを解除して開けることができる。有効:【盗賊の心得】【ロックスミス】", [1, 3, 5, 7, 9], [3, 6, 9, 12, 20], [3, 6, 9, 12, 20]),
  39. 24 => Row.new("頑丈な岩壁に阻まれた隠し財宝の部屋を発見する。岩壁は「打撃」属性で合計%s点のダメージを与えると破壊され、財宝ランク%sのアイテムを入手可能。岩壁はどのヘクスからでも隣接扱いで攻撃可能。", [100, 200, 300, 500, 1000], [2, 4, 6, 8, 10]),
  40. 25 => Row.new("ミミックの罠。ランダムなキャラクターに「3D+%s」の「斬撃」属性ダメージを与える。[知力-%s]判定に成功すればこの罠を見抜いて無効化でき、なおかつ%sGPを入手可能。有効:【盗賊の心得】【ロックスミス】", [30, 50, 70, 100, 300], [3, 6, 9, 12, 20], [1000, 2000, 5000, 10000, 30000]),
  41. 26 => Row.new("トレジャーイーターの罠。冒険中に入手したアイテム(消耗品・GP以外)を全て失う。[知力-%s]判定に成功すればこの罠を見抜いて無効化することができ、なおかつ%sGP入手可能。", [3, 6, 9, 12, 20], [1000, 2000, 5000, 10000, 30000]),
  42. 31 => Row.new("洞窟内で暗がりの中に近道を発見!有利な特異点「猫の目」を持つキャラクターがいればクリア時の財宝ランク+1。"),
  43. 32 => Row.new("洞窟内で近道を発見!だが狭くて通れるかどうか…?有利な特異点「軟体動物」を持つキャラクターがいればクリア時の財宝ランク+1。"),
  44. 33 => Row.new("6つの分かれ道だ、どちらに進めばいいのだろうか…?1D6を振って1~3が出ればクリア時の財宝ランク+1。4~6が出ればクリア時の財宝ランク-1。有効:「非凡な直感」"),
  45. 34 => Row.new("足場の悪い道だ。うまく降りられればいいが…。[敏捷-%s]判定に成功すればクリア時の財宝ランク+1。失敗すると判定を行ったキャラクターに[3D+20]の防護点無視ダメージ。有効:「軟体動物」", [3, 6, 9, 12, 20]),
  46. 35 => Row.new("大きな岩でふさがれた近道。力づくでどかせてやる![体力-%s]判定に成功すれば売り味の財宝ランク+1。失敗すると判定を行ったキャラクターは〔FP〕を5点消費する。", [2, 4, 6, 8, 15]),
  47. 36 => Row.new("6つの分かれ道だ、どうやら正解の道以外はエネミーの巣だが…。1D6を振って1が出ればクリア時の財宝ランク+1。2~6が出れば即座に洞窟のエンカウントイベントが発生する!有効:「非凡な直感」"),
  48. 41 => Row.new("水あめ状のボディに王冠をのせた、珍しいエネミーだ!エネミーとエンカウント。"),
  49. 42 => Row.new("獣の皮をかぶった魔族が狩った獲物の取り分でもめているようだ。彼らは興奮して争っているが、PCたちを見つけると向きを変えて襲い掛かってくる!エネミーとエンカウント。「マジカルクッキング」で持ち歩くタイプのものを作っていた場合、それを渡すことで戦闘を回避することもできる。"),
  50. 43 => Row.new("岩だと思って通りすぎようとしたら魔族だった!?エネミーとエンカウント。相手は洞窟で巧妙に擬態しており、〔先制〕に+10のボーナスを得る。有利な特異点「虫の知らせ」があれば〔先制〕ボーナスを無効化できる。"),
  51. 44 => Row.new("洞窟でトロッコに乗ったら暴走するギア魔族に追いかけられた!エネミーとエンカウント。トロッコに乗って逃げつつの戦闘になり、2ラウンド以内に倒せなければ轢かれてPC全員が「%s」の防護点無視ダメージを受ける。また、1ラウンドに1人誰かが行動を消費してトロッコを運転する必要があり、これに失敗すると即座に轢かれてしまう。轢かれると戦闘は終了する。PCにケイヴウォーカーがいればトロッコの運転を「支援ターン」で行える。", ["3D6+30", "3D6+30", "3D6+30", "3D6+100", "300"]),
  52. 45 => Row.new("炎の燃え盛る洞窟だ!運の悪いことに魔獣までいるようだ…。イベント詳細決定時に敵味方全員が「3D6+%s」の「火炎」属性ダメージを受ける。さらにエネミーとエンカウント。", [10, 20, 30, 50, 150]),
  53. 46 => Row.new("冷気に包まれた洞窟だ。更に氷の魔族や魔獣まで棲息している!イベント詳細決定時に敵味方全員が「3D+%s」の「冷気」属性ダメージを受ける。さらにエネミーとエンカウント。", [10, 20, 30, 50, 150]),
  54. 51 => Row.new("突然の落盤がエネミーを押しつぶす!戦闘中の場合、ランダムにエネミー1体を即死させ、ドロップ品も入手可能。それ以外の場合は特に何も起きない。「分類:ネームド」「分類:魔将」のエネミーには「3D+50」の防護点無視ダメージ。"),
  55. 52 => Row.new("採掘用のダイナマイトが打ち捨てられている。ケイヴウォーカー用の消耗品%sを持てるだけ持つことができる。", ["「ダイナマイト」", "「特性ダイナマイト」2個と「ダイナマイト」", "「特性ダイナマイト」4個と「ダイナマイト」", "「特性ダイナマイト」", "「ボンバーキング」(「電子の国のアリス」適用時)もしくは「特性ダイナマイト」(非適用時)"]),
  56. 53 => Row.new("洞窟内に有毒ガスが発生している!敵味方全員[抵抗-%s]で判定し、失敗したキャラクターは%s点の防護点無視ダメージを受ける。有効:【ガシンショウタン】", [4, 6, 8, 10, 15], [15, 30, 45, 60, 100]),
  57. 54 => Row.new("溶岩の流れる部屋だ、早くおさらばしたいところだが…。[敏捷-%s]判定に成功すれば何事も無く渡り切ることができる。失敗するとPC全員に「3D6+%s」の「火炎」属性ダメージ。PCにドラコニアンがいれば判定不要。有効:【野伏の歩み】", [3, 6, 9, 12, 20], [20, 40, 60, 90, 200]),
  58. 55 => Row.new("突然の落盤がPCのうちランダムに1人を押しつぶす!「3D6+%s」の防護点無視ダメージを受ける。「ドッジ-%s」で回避可能。有利な特異点「猫の目」か「虫の知らせ」があれば判定不要。", [40, 60, 80, 120, 400], [4, 6, 8, 10, 20]),
  59. 56 => Row.new("突然の地震が起きて洞窟全体が崩落を始める!このイベントが発生すると戦闘は強制終了する。PC全員[敏捷%s]で判定し、失敗したキャラクターは〔HP〕が0になる。〔HP〕が0以下だった場合は死亡してしまう。全員が判定に成功した場合、クリア時の財宝ランク+1。", ["", "-1", "-2", "-4", "-8"]),
  60. 61 => Row.new("プラネタリウムのように鉱石が輝く部屋。星の配置に関する謎かけになっている。行動を消費して[知力-%s]判定に成功するとこの謎を解くことができる。謎が解けると%sを入手可能。有効:【賢人の知恵】", [6, 9, 12, 15, 30], ["「うぃっしゅすたー」(大事なもの)か、10000GPの好きな方", "「うぃっしゅすたー」(大事なもの)2個か、20000GPの好きな方", "「うぃっしゅすたー」(大事なもの)3個か、30000GPの好きな方", "「うぃっしゅすたー」(大事なもの)5個か、50000GPの好きな方", "「wish star」(消耗品)"]),
  61. 62 => Row.new("地熱で温泉が湧いている!みんなで一休みできそうだ。このイベントが発生すると戦闘は強制終了する。PC全員の〔HP〕〔FP〕[Ft]が全回復する。また、シナリオ終了まで「ターン開始」時に〔HP〕が%s点ずつ回復する。", [5, 10, 15, 20, 30]),
  62. 63 => Row.new("地下渓流を発見する。どうやらここを進んでいくしかないようだ…。このラウンドではPCが「水中」にいるものとする。また、[敏捷-%s]判定に成功すると水中に沈んだ宝箱を発見する。中身は「%s」で、カギやトラップはかかっていない。行動を消費することで開けることができる。有効:【野伏の歩み】", [6, 9, 12, 15, 25], ["3D6x100GP", "(3D6+10)x100GP", "(3D6+30)x100GP", "3D6x1000GP", "3D6x10000GP"]),
  63. 64 => Row.new("とてつもない量のアダマン合金の原石を発見する!持ち帰り放題だ!「アダマン原石」は1つ%sGPで売却可能で、行動を消費することで自分のアイテム欄に好きなだけ入手可能。", [300, 500, 1000, 2000, 5000]),
  64. 65 => Row.new("地面から強力な重力で引きつけられる!敵味方全員が〔移動〕に-5のペナルティを受ける。さらに洞窟のエンカウントイベントが発生。「4-5」と「4-6」の部屋のダメージは適用しない。"),
  65. 66 => Row.new("怪しい光を放つ鉱石の部屋。鉱石は不気味な振動を放っており、ラウンド終了時にランダムなPC1人の武器が1つ壊れてシナリオ終了まで使用できなくなる。鉱石は「打撃」属性で合計%s点のダメージを与えると破壊される。鉱石はどのヘクスからでも隣接扱いで攻撃可能。", [100, 200, 300, 500, 1000]),
  66. }
  67. )
  68. 1 ruin = EventTable.new(
  69. "遺跡",
  70. 2,
  71. {
  72. 11 => Row.new("回復の泉。PC全員の〔HP〕〔FP〕が完全に回復する。「★死亡」以外のあらゆるBSも回復する。"),
  73. 12 => Row.new("随分進んだし一休みしよう。ラウンド数が奇数の場合は〔FP〕が「%s」回復する。ラウンド数が偶数の場合は進んだように見せかけて迷っているだけだった。どっと疲れてしまい〔FP〕は回復せず、クリア時の財宝ランク-1。有利な特異点「精緻な記憶」があれば、偶数ラウンドでも〔FP〕が回復して財宝ランクも減少しない。", ["3D6", "3D6+5", "3D6+10", "3D6+15", "3D6+30"]),
  74. 13 => Row.new("どうやらここは古代の医務室らしい。なにやら怪しげな機械がたくさんあるが…。[知力-%s]判定に成功すればPC全員の〔HP〕〔FP〕が完全に回復する。「★死亡」以外のあらゆるBSも回復する。有効:【魔導工学のススメ】", [3, 6, 9, 12, 18]),
  75. 14 => Row.new("「きみたちの道に光あれ…お金?いらないよ」道標の光ゴケを栽培している、苔のフラウに出会う。以後「いくつかの道から正解を選ぶ」イベントが発生した場合、光ゴケがそのうちの1つに飛んでいき、必ず正解の道を選ぶことができる。次が最終イベントだった場合、クリア時の財宝ランク+1。"),
  76. 15 => Row.new("ダンジョンの見取り図を書いた部屋に出る。次のランダムイベントでは、好きな地形を選択してからイベント表を振ることができる。次が最終イベントだった場合、クリア時の財宝ランク+1。"),
  77. 16 => Row.new("「パワーアップ装置!」と書かれた怪しげな機械が置いてある。%sGPを支払って使用するとキャラクターを強化(?)可能。使用するかは自由だが、不利な特異点「好奇心は猫を殺す」を持っているキャラクターはGPがあるなら入ってしまう。使用したキャラクターは1D6を振り、以下のような効果が発生する。
  78. ----------
  79. 1:なんと、ランダムな[主能力]が1点上昇する!(永久)
  80. 2:ただの日焼けサロンだ!健康的に焼け、シナリオ終了まで「火炎」に対する防護点+10。
  81. 3:CLが1上昇する!やったね!【特技】はシナリオが終了してから習得する。
  82. 4:装置は突然爆発する!ダメージは受けないが髪型がアフロに。装置は壊れる。
  83. 5:巨大化してシナリオ終了まで〔HP〕の最大値が+50!〔HP〕〔FP〕も全回復。装置は壊れる。
  84. 6:故障のせいかランダムな[主能力]が1点下降する…大ショック…(永久)
  85. [主能力]変動時は1D6を振ってどの能力が変動するか決定する。
  86. 1:体力 2:敏捷 3:感覚 4:知力 5:意志 6:使用者が選ぶ", [3000, 5000, 10000, 20000, 30000]),
  87. 21 => Row.new("財宝ランク%sの宝箱を発見する。カギやトラップはかかっていない。行動を消費することで開けることができる。", [0, 2, 4, 6, 8]),
  88. 22 => Row.new("財宝ランク%sの宝箱を発見する。難易度%sのカギがかかっている。行動を消費して[感覚-%s]判定でカギを解除して開けることができる。有効:【盗賊の心得】【ロックスミス】", [1, 3, 5, 7, 9], [3, 6, 9, 12, 20], [3, 6, 9, 12, 20]),
  89. 23 => Row.new("財宝ランク%sの宝箱を発見する。難易度%sのトラップがかかっている。行動を消費して[感覚-%s]判定でトラップを解除して開けることができる。有効:【盗賊の心得】【ロックスミス】", [1, 3, 5, 7], [3, 6, 9, 12, 20], [3, 6, 9, 12, 20]),
  90. 24 => Row.new("部屋で脱出ゲームのような様々な仕掛けをとかないと開かない宝箱。行動を消費して[知力-%s]判定に成功すれば開けることができ、財宝ランク%sのアイテムを入手可能。判定に失敗すると宝箱は爆発してしまい、中身も失われる。有効:【盗賊の心得】", [6, 9, 12, 15, 25], [2, 4, 6, 8, 10]),
  91. 25 => Row.new("ミミックの罠。ランダムなキャラクターに「3D+%s」の「斬撃」属性ダメージを与える。[知力-%s]判定に成功すればこの罠を見抜いて無効化でき、なおかつ%sGPを入手可能。有効:【盗賊の心得】【ロックスミス】", [30, 50, 70, 100, 300], [3, 6, 9, 12, 20], [1000, 2000, 5000, 10000, 30000]),
  92. 26 => Row.new("トレジャーイーターの罠。冒険中に入手したアイテム(消耗品・GP以外)を全て失う。[知力-%s]判定に成功すればこの罠を見抜いて無効化することができ、なおかつ%sGP入手可能。", [3, 6, 9, 12, 20], [1000, 2000, 5000, 10000, 30000]),
  93. 31 => Row.new("鏡に映る怪人が自分の真似をしろとジェスチャーしている。[敏捷-%s]判定に成功するとうまく真似してパントマイムすることができ、鏡が消滅して隠し通路が開かれる。クリア時の財宝ランク+1。【華劇:○○】を習得したフラウがいれば判定不要。", [6, 8, 10, 12, 16]),
  94. 32 => Row.new("小さな魔将の像がフィルトウィズの地図上で乱雑に置かれている。[知力-%s]判定に成功すれば魔将の所在地を正しく配置することができ、隠し通路が開かれる。クリア時の財宝ランク+1。有効:【賢人の知恵】", [6, 9, 12, 15, 20]),
  95. 33 => Row.new("シュートの罠に引っかかるが、結果的に新たな道を発見できた!このイベントが発生すると戦闘は強制終了する。PC全員が「3D+10」の「打撃」属性ダメージを受けるが、クリア時の財宝ランク+1。"),
  96. 34 => Row.new("ラダマンティス崇拝者が創りだした巨大な甲羅のようなものが置かれた部屋。登っていけば近道することができそうだが、これはかなり骨が折れそうだ…。行動を消費して[敏捷-%s]判定を行い、成功すればクリア時の財宝ランク+1。判定に挑戦したキャラクターは次のターンまで〔回避〕判定を行えない。有効:「軟体動物」【野伏の歩み】", [6, 9, 12, 15, 20]),
  97. 35 => Row.new("後ろから重い物が転がってくる音がする。ローリングストーンだ!このイベントが発生すると戦闘は強制終了する。ラウンド終了時に全員の〔移動〕が%s以上であればクリア時の財宝ランク+1。〔移動〕が%s未満のPCは「%s」の防護点無視ダメージを受ける。", [6, 8, 10, 12], [6, 8, 10, 12, 15], ["3D6+30", "3D6+50", "3D6+70", "3D6+100", "300"]),
  98. 36 => Row.new("通路が複雑に入り組んでおり道に迷いそうだ…。2D6を振り、ゾロ目ならクリア時の財宝ランク+1。それ以外の場合はクリア時の財宝ランク-1。有効:「非凡な直感」"),
  99. 41 => Row.new("絶体絶命、モンスターハウスだ!危機感を煽るBGMも流れてくる。これらのエネミーを全滅させた際、最後に倒したエネミーからは必ず「レア」を入手できる。イベント決定後に逃亡を宣言しても良い。その場合クリア時の財宝ランク-2。"),
  100. 42 => Row.new("石像が並んでいる通路があるが…なんと石像は警備装置だった!エネミーとエンカウント。奇襲攻撃のため、エネミーからの攻撃の〔回避〕に-4のペナルティを受ける。【魔導工学のススメ】があれば警戒していたため、このペナルティは受けない。"),
  101. 43 => Row.new("魔族が障害物に身を隠しながら狙撃してきた!エネミーとエンカウント。障害物のため、エネミーは近接攻撃に対する防護点に+30のボーナス。"),
  102. 44 => Row.new("「汝が戦う理由とは何か?答えい人間!」ブツゼンにモンスターが仁王立ちしており、問答を行ってくる。[意思-6]判定に成功すると戦闘を回避することができ、ドロップ品も入手可能。判定に失敗するか戦闘を望んだ場合、エネミーとエンカウント。有効:【詩人の交渉術】"),
  103. 45 => Row.new("進路上に鎖に繋がれたモンスターを発見する。どうやら普通のモンスターより凶暴なようだ、戦うべきか避けるべきか…エネミーとエンカウント。エネミーはあらゆる致傷力に+%sのボーナスを得る。戦闘を避けた場合クリア時の財宝ランク-1。", [10, 20, 30, 40, 100]),
  104. 46 => Row.new("暴れゴーレムが襲い掛かってくる!暴走しているせいか凄まじいスピードだ!エネミーとエンカウント。このエネミーは〔移動〕〔先制〕に+10のボーナスを得ており、全員が行動終了した後、ラウンド終了前にもう1度ターンがまわってくる。"),
  105. 51 => Row.new("一斉に周囲の壁の射出口が開き、無数の矢が放たれる!PC全員に「%s」の「刺突」属性ダメージ。「ドッジ-%s」で〔回避〕が可能。有利な特異点「虫の知らせ」があれば〔回避〕に+4のボーナスを得る。", ["3D6+20", "3D6+40", "3D6+60", "3D6+90", "200"], [4, 6, 8, 10, 20]),
  106. 52 => Row.new("突然部屋に白いガスが充満して睡魔が襲ってくる!PC全員が「☆眠り」を受ける。[抵抗-%s]判定で無効化。", [2, 4, 6, 8, 12]),
  107. 53 => Row.new("フロアイミテーターの罠だ!突然部屋の入口が閉まり、君たちを消化し始める!「斬撃」属性で合計%s点のダメージを与えると入り口が開き脱出できるが、それまでPC全員は「ターン開始」時に%s点の防護点無視ダメージを受ける。ラウンドごとの地形変化やイベントは行われず、最終イベントにも進めなくなる。入り口はどのヘクスからでも隣接扱いで攻撃可能。誰も「斬撃」属性の攻撃ができないなら君たちの冒険はここまでだ。", [100, 200, 300, 500, 1000], [10, 20, 30, 40, 60]),
  108. 54 => Row.new("休憩室のようだ。寝心地のよさそうなふかふかのベッドまである。このイベントが発生すると戦闘は強制終了する。PC全員が[意思-%s]判定を行い、失敗したPCは「☆眠り」を受ける。この「☆眠り」は誰かが行動を消費して叩き起こさない限り、シナリオ終了まで持続する。全員が判定に失敗した場合、君たちの冒険はここまでだ。もう目覚めることはないが、せめていい夢を見られるといいだろう。ホムンクルスは「居眠り禁止」を厳命されているため、「☆眠り」を受けない。", [2, 4, 6, 8, 12]),
  109. 55 => Row.new("「ラダマンティスの蛇」の像と目が合ってしまった。どうやらダンジョンの監視者に見つかってしまったらしい!以後探索中にエネミーと遭遇した場合、CLの最も高いエネミーが1体増加する。このイベントの効果は累積せず、「分類:ネームド」「分類:魔将」のエネミーの数は変化しない。"),
  110. 56 => Row.new("怪しげな卵が置かれた部屋。君たちが近寄ると卵が割れて…?1D6を振り、その出目によって中から様々なものが出現する。
  111. ----------
  112. 1~2:これは財宝だ!財宝ランク%sのアイテムが入手可能。
  113. 3~4:卵はそのまま大爆発!PC全員に「%s」の「打撃」「火炎」属性ダメージ。
  114. 5~6:卵からドラゴンが!エネミーとエンカウント。", [2, 4, 6, 8, 10], ["3D6+30", "3D6+50", "3D6+70", "3D6+100", "300"]),
  115. 61 => Row.new("突然ダンジョンの明かりが消えてほぼ真っ暗になってしまう!次のラウンドに入るまであらゆる判定に-6のペナルティを受ける。有利な特異点「猫の目」があればペナルティを受けない。また「洞窟1-5の懐中電灯」や「遺跡1-4の光ゴケ」などがあれば無効。"),
  116. 62 => Row.new("どうやら古代の訓練施設のようだ。「パンチングマシーン」と書かれたものがあり、行動を消費すれば100GPを支払って挑戦可能。「格闘」武器でのダメージ判定を1回行い、与えたダメージによってファンファーレとともに景品が出る。1回挑戦すると、ガタが来ていたのか壊れてしまう。
  117. ----------
  118. ダメージ%s以上:財宝ランク%sのアイテム
  119. ダメージ%s以上:財宝ランク%sのアイテム
  120. ダメージ%s以上:財宝ランク%sのアイテム", [20, 40, 60, 80, 200], [0, 2, 4, 6, 8], [30, 50, 70, 90, 400], [1, 3, 5, 7, 9], [40, 60, 80, 100, 600], [2, 4, 6, 8, 10]),
  121. 63 => Row.new("謎の装置のせいで気になるあの子と体が入れ替わってしまった!?シナリオ終了までPCのうち2人の体や能力が入れ替わってしまう。入れ替わるキャラクターはランダムで決定するか、面白くなるようにGMが選ぶ。戦闘で扱うデータは今までどおりだが、入れ替わったキャラクターのロールプレイを行うこと。"),
  122. 64 => Row.new("やった、きんきらきんの宝物庫だ!「2-1」「2-2」「2-3」の宝箱が3つ同時に出現する。ただし、「2-3」の罠の解除に失敗すると、宝箱を開けようとしたキャラクターは黄金像になってしまう。めでたく財宝の仲間入りだ。「☆石化」と同様に扱うが、シナリオ終了までいかなる手段でも治せない。"),
  123. 65 => Row.new("キャンディークラウンハウスだ!エネミーとエンカウント。4ラウンド終了までに1体も倒せなかった場合、チャンスを逃した悔しさからPC全員が〔FP〕に「逃げたキャンディークラウンの数x5」の防護点無視ダメージを受ける。"),
  124. 66 => Row.new("なぜここに呼ばれたかお分かりになりますでしょうか?ラダマンティス崇拝者の作りだした審判の部屋に飛ばされてしまった!ラウンド終了時に部屋の中央のラダマンティス像から裁きの光が放たれ、PC全員が「%s」の防護点無視ダメージを受ける。%s点のダメージを与えれば破壊可能でダメージも受けない。ラダマンティス像はどのヘクスからでも隣接扱いで攻撃可能。破壊に成功すると財宝ランク%sのアイテムが入手可能。", ["3D6+50", "3D6+80", "3D6+110", "3D6+150", "400"], [200, 400, 600, 1000, 2000], [3, 5, 7, 9, 11]),
  125. }
  126. )
  127. 1 mountain = EventTable.new(
  128. "山岳",
  129. 3,
  130. {
  131. 11 => Row.new("回復の泉。PC全員の〔HP〕〔FP〕が完全に回復する。「★死亡」以外のあらゆるBSも回復する。"),
  132. 12 => Row.new("休憩に丁度いい広場を見つけた。〔FP〕が3D6%s点回復する!だが、居心地が良すぎて離れづらくなってしまう。PC全員が[意思-%s]判定を行う。PCのうち半分以上が失敗した場合、次のラウンドもこのイベントが発生して、クリア時の財宝ランク-1。", ["", "+5", "+10", "+15", "+30"], [2, 3, 4, 6, 9]),
  133. 13 => Row.new("山小屋を発見し一休み。〔HP〕と〔FP〕が3D6%s点回復する。PCが4人の時にこのイベントが発生した場合、休憩中の暇つぶしに山小屋の四隅をぐるぐるまわって運動し始める。だが、後から妙なことに気が付きFtが1点減少する…", ["", "+5", "+10", "+15", "+30"]),
  134. 14 => Row.new("「へーっ、こんなとこまでよく来たね!これ、食べる?食べる?」キイチゴを栽培しているフラウに出会う。栄養満点で幸せになる。PC全員の〔HP〕と〔FP〕を10点、Ftを1点回復することができる。さらに、【魔法の料理人】を持つPCがいれば、消耗品「いちごジャム」をSLv個入手可能。
  135. ----------
  136. 名称:いちごジャム
  137. 価格:非売品
  138. 解説:〔HP〕と〔FP〕を10点、Ftを1点回復する。戦闘中には使用できない。"),
  139. 15 => Row.new("少し休憩できそうな洞窟を発見する。PC全員の〔FP〕を10点回復する。中には他のエクスプローラーが残していったと思われる道具もあった。「%s」を入手することができる。大雨が降っていたり、火災が起こったりしていた場合、その効果も消滅する。", ["高級HPポーション", "最高級HPポーション", "特性HPポーション", "うぃっしゅすたー", "うぃっしゅすたーx3"]),
  140. 16 => Row.new("回復の泉。PC全員の〔HP〕〔FP〕が完全に回復する。%s「★死亡」以外のあらゆるBSも回復する。しかし山間の貴重な水源のため亜人によって管理されており、使用するには%sGPが必要。PCのパーティーに管理している亜人と同じ種族がいるか、【詩人の交渉術%s】を持つキャラクターがいれば無料で使用可能。どの種族が管理しているかは1D6を振って決定する。
  141. ----------
  142. 1:ドラコニアン
  143. 2:リザードとワイズマン
  144. 3:フラウ
  145. 4:シルヴァテイル
  146. 5:ストームコーザー
  147. 6:グラント", ["", "", "", "", "また、フォーチュンも最大値を越えて1増加する。"], [500, 1000, 2000, 4000, 30000], [1, 2, 3, 4, 5]),
  148. 21 => Row.new("財宝ランク%sの宝箱を発見する。カギやトラップはかかっていない。行動を消費することで開けることができる。", [0, 2, 4, 6, 8]),
  149. 22 => Row.new("財宝ランク%sの宝箱を発見する。難易度%sのカギがかかっている。行動を消費して[感覚-%s]判定でカギを解除して開けることができる。有効:【盗賊の心得】【ロックスミス】", [1, 3, 5, 7, 9], [3, 6, 9, 12, 20], [3, 6, 9, 12, 20]),
  150. 23 => Row.new("財宝ランク%sの宝箱を発見する。難易度%sのトラップがかかっている。行動を消費して[感覚-%s]判定でトラップを解除して開けることができる。有効:【盗賊の心得】【ロックスミス】", [1, 3, 5, 7, 9], [3, 6, 9, 12, 20], [3, 6, 9, 12, 20]),
  151. 24 => Row.new("狭い谷底に宝箱があるのが見える。そして手元には岩とロープが。これはもうバンジージャンプで取ってくるしかない!行動を消費して[敏捷-%s][意思-%s]で判定を行い、両方に成功すれば財宝ランク%sのアイテムを入手できる。[敏捷]判定がファンブルだった場合ロープがちぎれてしまい、4ラウンド目が終了するまで戻ってこれない。有効:【野伏の歩み】([敏捷]判定のみ)", [3, 6, 9, 12, 16], [3, 5, 7, 9, 12], [3, 5, 7, 9, 11]),
  152. 25 => Row.new("ミミックの罠。ランダムなキャラクターに「3D+%s」の「斬撃」属性ダメージを与える。[知力-%s]判定に成功すればこの罠を見抜いて無効化でき、なおかつ%sGPを入手可能。有効:【盗賊の心得】【ロックスミス】", [30, 50, 70, 100, 300], [3, 6, 9, 12, 20], [1000, 2000, 5000, 10000, 30000]),
  153. 26 => Row.new("トレジャーイーターの罠。冒険中に入手したアイテム(消耗品・GP以外)を全て失う。[知力-%s]判定に成功すればこの罠を見抜いて無効化することができ、なおかつ%sGP入手可能。", [3, 6, 9, 12, 20], [1000, 2000, 5000, 10000, 30000]),
  154. 31 => Row.new("山歩きの達人だけが発見できるショートカットコース。%sを持つキャラクターがいればクリア時の財宝ランク+1。", ["有利な特異点「鷹の目」か【野伏の歩み】", "有利な特異点「鷹の目」2段階か【野伏の歩み2】", "有利な特異点「鷹の目」2段階か【野伏の歩み3】", "有利な特異点「鷹の目」2段階か【野伏の歩み4】", "有利な特異点「鷹の目」必須かつ【野伏の歩み4】"]),
  155. 32 => Row.new("鉱物を運んでいたのであろう、運搬用トロッコを発見する。うまく運転できれば素早く進行できそうだが…?[敏捷-%s]判定に成功すればクリア時の財宝ランク+1。判定に失敗すると脱線して放り出されてしまい、PC全員が「3D+10」の防護点無視ダメージを受ける。PCにケイヴウォーカーがいれば判定不要。", [3, 6, 9, 12, 16]),
  156. 33 => Row.new("険しい斜面が続く。これは体力勝負になりそうだ…。PC全員が[体力%s]判定を行い、全員が成功すればクリア時の財宝ランク+1。判定に失敗したキャラクターは〔FP〕を%s点失う。", ["", "-1", "-2", "-4", "-8"], [5, 10, 15, 20, 30]),
  157. 34 => Row.new("空を飛べればショートカットできそうな崖を発見する。なんらかの飛行手段のあるPCがいる場合、クリア時の財宝ランク+1。元々飛行できなくてもラウンド中に【フライト】などの【特技】を使用してラウンド終了時に「飛行状態」であれば良い。"),
  158. 35 => Row.new("遠くから山彦のような不思議な声が聞こえる。山彦と会話をすると迷いやすい道を教えてくれるが、大声で会話をしているのでエネミーに見つかりやすくなる。会話をするなら次のイベントは必ず山岳のエンカウントイベントになり、会話を諦めるならクリア時の財宝ランク-1。有利な特異点「天体時計」があれば会話を諦めてもデメリットはない。"),
  159. 36 => Row.new("急に突風が吹いてきて、体力のないものは吹き飛ばされてしまう!もっとも[体力]の低いPC1人が[体力-%s]判定を行い、失敗すると「%s」の防護点無視ダメージを受ける。さらに、救助に時間がかかるためクリア時の財宝ランク-1。PCにストームコーザーがいればイベントの効果を無視できる(演出は自由)。", [2, 3, 4, 6, 9], ["3D6+20", "3D6+40", "3D6+60", "3D6+90", "200"]),
  160. 41 => Row.new("高いところから多数の岩がごろごろと…いや、これは魔物だ!エネミーとエンカウント。高低差で勢いがついているため、エネミーは〔移動〕に+5、%sのボーナスを得る", ["物理攻撃の致傷力に+10", "物理攻撃の致傷力に+30", "物理攻撃の致傷力に+60", "物理攻撃の致傷力に+120", "あらゆる攻撃の致傷力に+100"]),
  161. 42 => Row.new("空中から羽をもった魔物があちこちから攻撃を仕掛けてきた!エネミーとエンカウント。エネミーのうち%s体は任意の「PC配置ヘクス」に設置される。", [3, 3, 1, 1, 3]),
  162. 43 => Row.new("「た、隊長、もうダメです!」「バカもん!この程度で根を上げるな!」登山訓練中の魔族の小隊と出くわす。だが相手は疲れているようだ?エネミーとエンカウント。〔FP〕は最大値から10点減少している。"),
  163. 44 => Row.new("山道の横から突然穴が空き、魔物と鉢合わせしてしまう!エネミーとエンカウント。PC全員が[感覚-3]判定を行い、失敗したキャラクターはそのラウンド中に行動することができない。(〔回避〕や[抵抗]の判定、自分のターン以外で行う【特技】は可能)有効:「狐の耳」"),
  164. 45 => Row.new("ケタケタ笑いながら空から襲撃される。エネミーとエンカウント。彼女達はとても飽きっぽいので2ラウンド行動した後、3ラウンド目の開始前に立ち去ってしまう。(ドロップは入手できない)"),
  165. 46 => Row.new("フェニックスがつがいで暮らす縄張りに足を踏み入れてしまった!エネミーとエンカウント。すぐに引き返せば戦闘を回避できるが、クリア時の財宝ランク-1。そのまま進むのであれば[意思-6]で判定を行い、成功すれば見逃してもらうことができる。失敗するとフェニックスは怒り狂い、襲ってくる。有効:【詩人の交渉術】"),
  166. 51 => Row.new("ジャーンジャーン!げぇ、落石だ!!上から魔族が岩を落とし始める。PC全員に「%s」点の「打撃」属性ダメージ。「ドッジ-%s」で〔回避〕が可能。", ["3D6+20", "3D6+40", "3D6+60", "3D6+90", "200"], [3, 5, 7, 9, 15]),
  167. 52 => Row.new("ファイトー!いっぱーつ!!足場が崩れ出す。PC全員が[敏捷-%s]判定を行い、失敗すると「%s」点の防護点無視ダメージを受ける。成功したPCは[体力]判定を行い、失敗したPC1人を支えることができる。この判定に失敗した場合、支えようとしたキャラクターも一緒にダメージを受ける。有効:【野伏の歩み】", [3, 6, 9, 12, 20], ["3D6+20", "3D6+40", "3D6+60", "3D6+90", "200"]),
  168. 53 => Row.new("滑りやすい岩を飛び移っていく道が続いている。敵味方全員が[敏捷-%s]で判定を行い、失敗したキャラクターは「☆転倒」を受ける。飛行可能なキャラクターはこの影響を受けない。有効:【野伏の歩み】", [2, 2, 4, 6, 10]),
  169. 54 => Row.new("先に進む道に『銀糸の甲殻』アルゲントゥムの巣がびっしり張られている。幸い主はいないようだが、巣が邪魔で移動がしにくい…敵味方全員が4ラウンド目まで飛行状態になれなくなり、〔移動〕にも-5のペナルティを受ける。不利な特異点「トラウマ:虫」などがあればそれも適用する。"),
  170. 55 => Row.new("美しい万年雪の中を進んでいたと思ったのも束の間、雪崩に遭遇してしまう!全員が「%s」点の「打撃」「冷気」属性ダメージを受け、クリア時の財宝ランク-2。[感覚-%s]の判定に成功すれば、すぐに洞窟に避難してやり過ごすことができる。洞窟の中には%sがあり、入手可能。有効:「狐の耳」【野伏の歩み】", ["3D6+30", "3D6+50", "3D6+70", "3D6+100", "300"], [6, 9, 12, 15, 20], ["スノーの結晶(装飾品/3000GP)", "紺碧の瞳(装飾品/10000GP)", "氷狼の爪(装飾品/25000GP)", "氷河龍の盾(盾/65000GP)", "コキュートスダガー(ナイフ/110000GP)"]),
  171. 56 => Row.new("���から魔族の大群が登ってくる!ジャーンジャーン!石を落として撃退だ!魔族の群れは射撃攻撃で合計%s点のダメージを与えれば撃退可能。複数の対象を攻撃できる【特技】を使用した場合は、ダメージを2回計算可能。ラウンド終了時までに撃退できなかった場合、PC全員が撃破に足りなかったダメージに等しい防護点無視ダメージを受ける。魔族の群れはどのヘクスからでも攻撃可能だが、射程が10ヘクス以上の攻撃でなければならない。石を落としても攻撃可能で、「3D+%s」点の「打撃」属性ダメージを与える。この攻撃は判定なしで自動的に命中する。", [100, 200, 300, 500, 1200], [10, 20, 30, 50, 100]),
  172. 61 => Row.new("急に大雨が降り出した、屋内に避難したいところだが…地形が「洞窟」か「遺跡」に変更されるまで、ラウンド終了時、〔FP〕に「%s」点の防護点無視ダメージを受ける。〔FP〕に受けるダメージはPCがそれぞれダイスを振って決定する。「水中行動」が可能なPCはこの効果を受けない。", ["1D6", "2D6", "3D6", "3D6+5", "3D6+15"]),
  173. 62 => Row.new("色とりどりの石が岩肌に…これはカラーストーンの原石だ![知力-%s]判定に成功すればカラーストーン原石を持ち帰ることができる。「カラーストーン原石」は1つ%sGPで売却可能で、行動を消費することで自分のアイテム欄に好きなだけ入手可能。有効:【魔導工学のススメ】", [6, 9, 12, 15, 20], [500, 1000, 2000, 3000, 5000]),
  174. 63 => Row.new("不思議な岩がある。1D6を振って1~2であれば「火炎」属性、3~4であれば「冷気」属性、5~6であれば「電撃」属性の攻撃で、4ラウンド目終了までに%s点のダメージを与えれば破壊可能。不思議な岩はどのヘクスからでも隣接扱いで攻撃可能で、破壊したあとには財宝ランク%sのアイテムが発見できる。", [30, 60, 100, 200, 500], [2, 4, 6, 8, 10]),
  175. 64 => Row.new("「こんなところで人間に会うなんて珍しいな、お前らも食っていくか?」ストームコーザーが獲物を取った後調理している。このイベントが発生するとエネミーは消滅する。マジカルクッキングLv4「ジャンボ串焼き」を食べさせてもらえる。【魔法の料理人】を習得したPCがいれば、Lv5「グラント風香草焼き」にパワーアップする。この料理の効果は、自分たちが「マジカルクッキング」で作った料理と累積する。"),
  176. 65 => Row.new("高山植物の群生地を発見する。ポーションの材料になるものもありそうだ?[知力-%s]判定に成功すれば、薬草を持ち帰ることができる。「高山の薬草」は1つ%sGPで売却可能で、行動を消費することで自分のアイテム欄に好きなだけ入手可能。【ポーションナレッジ】があれば判定は不要。有効:【賢人の知恵】「自然と生きる」", [6, 9, 12, 15, 20], [500, 1000, 2000, 3000, 5000]),
  177. 66 => Row.new("岩壁が大きく崩れていく!崩落に巻き込まれて入口付近まで戻されてしまい、クリア時の財宝ランク-2。だが、崩落した後に鈍く輝くアイテムが転がっている…?[感覚-%s]判定に成功すれば%sを入手可能。有効:「鷹の目」", [6, 9, 12, 15, 20], ["アダマンソード(剣/8000GP)", "アダマンスケイル(鎧/15000GP)", "アダマンプレート(鎧/30000GP)", "ヒュージーブレード(剣/45000GP)", "封印の手錠(盾/200000GP)"]),
  178. }
  179. )
  180. 1 waterside = EventTable.new(
  181. "水辺",
  182. 4,
  183. {
  184. 11 => Row.new("回復の泉。PC全員の〔HP〕〔FP〕が完全に回復する。「★死亡」以外のあらゆるBSも回復する。"),
  185. 12 => Row.new("甲羅干しに適した暖かい小島を見つける。少しだけ休憩しよう。〔HP〕と〔FP〕が「3D%s」点回復する。ワイズマンのPCは全回復する。何か面白い寝言を言ったPCに「%s」が空から降ってくる。", ["", "+5", "+10", "+15", "+30"], ["HPポーション", "高級HPポーション", "最高級HPポーション", "うぃっしゅすたー", "蘇生ポーション"]),
  186. 13 => Row.new("魚の群れを発見!捕まえてたらふくいただくとしよう!【魔法の料理人】があればマジカルクッキングの「魔界魚の目玉」(Lv3)%sの効果を得られる。この効果はすでにマジカルクッキングを使用していても累積する。", [
  187. "",
  188. "、【魔法の料理人2】があれば「シルヴァまっしぐら」(Lv4)と「エドマエスシ」(Lv5)の全て",
  189. "、【魔法の料理人2】があれば「シルヴァまっしぐら」(Lv4)と「エドマエスシ」(Lv5)、【魔法の料理人3】があれば「刺身盛り合わせ」(Lv6)と「オオトロスシ」(Lv7)の全て",
  190. "、【魔法の料理人2】があれば「シルヴァまっしぐら」(Lv4)と「エドマエスシ」(Lv5)、【魔法の料理人3】があれば「刺身盛り合わせ」(Lv6)と「オオトロスシ」(Lv7)、【魔法の料理人4】があれば「特上うな丼」(Lv8)の全て",
  191. "、【魔法の料理人2】があれば「シルヴァまっしぐら」(Lv4)と「エドマエスシ」(Lv5)、【魔法の料理人3】があれば「刺身盛り合わせ」(Lv6)と「オオトロスシ」(Lv7)、【魔法の料理人4】があれば「特上うな丼」(Lv8)、【魔法の料理人5】で全員のフォーチュン+1(最大値をこえる)の全て"
  192. ]),
  193. 14 => Row.new("「こんにちは、スーっとして気持ちいいよ。…ふふ、一緒に入ろうか?」ミントや菖蒲を育てているフラウに出会い、薬湯に浸かって〔FP〕が全回復する。さらに、「火炎」属性に対する防護点に+10のボーナス。"),
  194. 15 => Row.new("リザードの集落につく。〔HP〕の減ったキャラクターがいれば持て囃され、マジカルクッキング「カリカリミミズ肉」(Lv2)をごちそうしてもらい、この先の道案内も買って出てくれる。クリア時の財宝ランク+1。全員の〔HP〕が満タンの場合は、そっけない扱いをされ何も起こらない。この効果はすでにマジカルクッキングを使用していても累積する。"),
  195. 16 => Row.new("回復の泉に見せかけた毒の泉。パーティーメンバーの〔HP〕〔FP〕のいずれかが減少している場合このイベントは拒否できない。毒の水で「%s」点の防護点無視ダメージを受ける。〔HP〕〔FP〕が全快のキャラクターと「虫の知らせ」があるPCはこの効果を受けない。[知力-6]判定に成功すればこれが毒の泉だとわかる。有効:【野伏の歩み】【賢人の知恵】", ["3D6+10", "3D6+20", "3D6+30", "3D6+50", "100"]),
  196. 21 => Row.new("財宝ランク%sの宝箱を発見する。カギやトラップはかかっていない。行動を消費することで開けることができる。", [0, 2, 4, 6, 8]),
  197. 22 => Row.new("財宝ランク%sの宝箱を発見する。難易度%sのカギがかかっている。行動を消費して[感覚-%s]判定でカギを解除して開けることができる。有効:【盗賊の心得】【ロックスミス】", [1, 3, 5, 7, 9], [3, 6, 9, 12, 20], [3, 6, 9, 12, 20]),
  198. 23 => Row.new("財宝ランク%sの宝箱を発見する。難易度%sのトラップがかかっている。行動を消費して[感覚-%s]判定でトラップを解除して開けることができる。有効:【盗賊の心得】【ロックスミス】", [1, 3, 5, 7, 9], [3, 6, 9, 12, 20], [3, 6, 9, 12, 20]),
  199. 24 => Row.new("水中の奥深くに宝箱があるのが見える。とってくるのは無理そうに見えるが…行動を消費して[敏捷-%s]判定を行い、成功すれば財宝ランク%sのアイテムを入手できる。有利な特異点「水中行動」があれば判定不要。有効:【野伏の歩み】", [9, 12, 15, 18, 25], [3, 5, 7, 9, 11]),
  200. 25 => Row.new("ミミックの罠。ランダムなキャラクターに「3D6+%s」の「斬撃」属性ダメージを与える。[知力-%s]判定に成功すればこの罠を見抜いて無効化でき、なおかつ%sGPを入手可能。有効:【盗賊の心得】【ロックスミス】", [30, 50, 70, 100, 300], [3, 6, 9, 12, 20], [1000, 2000, 5000, 10000, 30000]),
  201. 26 => Row.new("トレジャーイーターの罠。冒険中に入手したアイテム(消耗品・GP以外)を全て失う。[知力-%s]判定に成功すればこの罠を見抜いて無効化することができ、なおかつ%sGP入手可能。", [3, 6, 9, 12, 20], [1000, 2000, 5000, 10000, 30000]),
  202. 31 => Row.new("進みやすい浅瀬が続き、すいすいと進める。クリア時の財宝ランク+1。有利な特異点「水中行動」や【ミズグモ】をもつPCがいればクリア時の財宝ランク+2。ただしグラントがいると浅瀬にもかかわらず溺れてしまい、財宝ランクは変化しない。(RP次第でグラントがいるデメリットをなくしても良い)"),
  203. 32 => Row.new("様々な漂流物が流れこむ船の墓場だ。お宝もありそうだが探索は大変そうだ…〔FP〕を3点消費する代わりに水辺の財宝系イベント「2-1~2-6」が発生する。この効果を望まない場合は特に何も起きない。"),
  204. 33 => Row.new("ヒャッハー、ウォータースライダーだ!巨大な植物の幹を滑って進むことができるが、かなり怖いので勇気が必要。PC全員が[意思%s]判定を行い、全員成功すればクリア時の財宝ランク+1。この判定に成功したPCは、失敗したPCを1人まで抱えて滑り落ちることで成功扱いにできる。", ["", "-1", "-2", "-4", "-8"]),
  205. 34 => Row.new("大蓮のような植物の群生地を渡っていく。重たい装備を身に着けていると沈んでしまいそうだ…[必要体力]が15以上の装備を所有しているPCがいるとクリア時の財宝ランク-1。そのPCに有利な特異点「水中行動」や【ミズグモ】があればこのデメリットは受けない。"),
  206. 35 => Row.new("水流が複雑になっており、思うように進めず戻されてしまう。[体力-%s]判定に失敗するとクリア時の財宝ランク-1。", [4, 5, 6, 8, 12]),
  207. 36 => Row.new("突然の激流にイカダが巻き込まれる!身を任せている場合じゃない!敵味方全員が[敏捷-%s]判定を行い、失敗したキャラクターは4ラウンド終了まで帰ってこれなくなる。全員が失敗してしまった場合、冒険は強制的に失敗となりダンジョンの入口に戻されてしまう。ダンジョン内で手に入れたアイテムも消耗品とGP以外は全て水に流されて消滅する。有効:【野伏の歩み】", [2, 3, 4, 6, 10]),
  208. 41 => Row.new("蟹の魔物がイカダをちょんぎろうとしている!早く倒さなくては!エネミーとエンカウント。1ラウンド以内に倒せなかった場合、イカダをちょんぎられてクリア時の財宝ランク-1。"),
  209. 42 => Row.new("アシガル潜水隊と遭遇。エネミーとエンカウント。エネミーは奇襲攻撃を仕掛けてくるため〔先制〕に+5のボーナスを得る。%s", [
  210. "[感覚-6]判定に成功すると水面に動く竹筒を発見可能で、その場合は〔先制〕へのボーナスは無効化可能。有効:「鷹の目」",
  211. "[感覚-8]判定に成功すると水面に動く竹筒を発見可能で、その場合は〔先制〕へのボーナスは無効化可能。有効:「鷹の目」",
  212. "[感覚-10]定に成功すると水面に動く竹筒を発見可能で、その場合は〔先制〕へのボーナスは無効化可能。有効:「鷹の目」",
  213. "[感覚-12]判定に成功すると水面に動く竹筒を発見可能で、その場合は〔先制〕へのボーナスは無効化可能。有効:「鷹の目」",
  214. "",
  215. ]),
  216. 43 => Row.new("何か水面が揺れている…まさか、あれはニンジャ!?エネミーとエンカウント。エネミーは謎の光学迷彩ギアで姿を隠しており、〔回避〕に+%sのボーナス。", [2, 2, 4, 6, 2]),
  217. 44 => Row.new("水辺で花を育てている少女に出会う…が、少女は魔族だった!エネミーとエンカウント。彼女が育てている花の根元には無数の動物の死体が無残にも肥料にされている。戦闘開始時に[意思]判定を行い、失敗したキャラクターは戦慄して1ターン行動不可。〔回避〕[抵抗]の判定を行うことはできる。"),
  218. 45 => Row.new("高波にのった魔族の騎士が現れる!エネミーとエンカウント。エネミーは波で勢いがついているため、最初のターンは〔移動〕〔先制〕に+5のボーナス。"),
  219. 46 => Row.new("湖の上を渡っていると思ったら巨大なスライムの上だった!?エネミーとエンカウント。エネミーは巨大なため〔HP〕に+%sのボーナスを得ている。また、全てのヘクスに対して隣接しているものとする。(移動妨害も全てのヘクスで受ける)", [50, 100, 150, 250, 1500]),
  220. 51 => Row.new("美しい歌声が響き渡る、意識が引きずり込まれそうだ。その場にいる敵味方全員は[抵抗-%s]判定を行い、失敗すると1ターン「☆眠り」を受ける。有効:【音響補正装置】", [2, 4, 6, 8, 12]),
  221. 52 => Row.new("小舟で進んでいると、なにやら激しい水の音がする。この先は滝のようだ!PC全員が[移動-%s]判定を行い(「水中行動」があれば+5のボーナスを得る)、成功したキャラクターがいれば事なきを得る。更に滝の裏の洞窟から財宝ランク%sのアイテムを入手可能。〔移動〕判定に全員失敗した場合、全員が滝から転落して「%s」の防護点無視ダメージを受ける。有効:【野伏の歩み】", [3, 4, 5, 7, 12], [3, 5, 7, 9, 11], ["3D6+20", "3D6+30", "3D6+40", "3D6+60", "150"]),
  222. 53 => Row.new("船の墓場を進んでいると、強風でマストが倒れてくる!PC全員が「ドッジ-%s」判定を行い、失敗すると「%s」の防護点無視ダメージを受け、「☆転倒」を受ける。", [2, 4, 6, 8, 15], ["3D6+10", "3D6+20", "3D6+30", "3D6+50", "150"]),
  223. 54 => Row.new("ぺっぺっ、水がしょっぱい!濃い塩水がギアをダメにしてしまう。所有している武器についたアタッチメント1つがシナリオ終了まで消滅してしまう。どのアタッチメントが消滅するかは選択可能。【魔導工学のススメ%s】があれば応急処置を行い、この効果を受けない。また、「★特別アタッチメント」は消滅しない。", [1, 1, 2, 3, 4]),
  224. 55 => Row.new("とても寒く冷たい水辺で、体力をどんどん奪われてしまう。「冷気」属性に対する防護点が%s以下のキャラクターは、ラウンド終了時に〔FP〕を%s点失う。", [10, 15, 20, 25, 50], [5, 10, 15, 20, 30]),
  225. 56 => Row.new("突然間欠泉が噴き出してダメージを受ける!敵味方全員のうちランダムで1体に「%s」点の「火炎」属性ダメージと「☆転倒」を与える。このイベントが2ラウンド目で発生した場合、4ラウンド目のイベントはダイスを振らず「洞窟6-2」の温泉イベントになる。", ["3D6+40", "3D6+60", "3D6+80", "3D6+120", "400"]),
  226. 61 => Row.new("傷ついた%sを発見する。ラウンド終了までに〔HP〕を%s点まで回復させればなついて%sを入手可能。回復できなかった場合、%sは逃走する。", ["スワンプランナー", "スカイサーチャー", "グリマルキン", "ゴールデンコーン", "プチブレイザー"], [30, 50, 70, 100, 400], ["スワンプランナー(ペット/4000GP)", "スカイサーチャー(ペット/6000GP)", "グリマルキン(ペット/15000GP)", "ゴールデンコーン(ペット/30000GP)", "プチブレイザー(ペット/100000GP)"], ["スワンプランナー", "スカイサーチャー", "グリマルキン", "ゴールデンコーン", "プチブレイザー"]),
  227. 62 => Row.new("なにやら派手な魚を見つける。あれはもしやアズマに伝わる幻の魚「ニシキゴイ」か!?行動を消費して[敏捷-%s]判定に成功すれば見事捕まえ、アイテム欄に入手することができる。売却すると%sGPになる。この判定は4ラウンド目が終了するまで何度でも行うことができる。有効:【野伏の歩み】", [8, 10, 12, 15, 25], [3000, 6000, 12000, 24000, 120_000]),
  228. 63 => Row.new("カエルの合唱が響き渡る。何やら意味がある歌声に聞こえるが…[知力-%s]判定に成功すると歌の意味を理解できる。カエル達は安全な道を教えてくれていたのだ!判定に成功した場合クリア時の財宝ランク+1。判定に失敗すると毒の沼に足を踏み入れ、PC全員が「%s」点の防護点無視ダメージを受ける。有効:「自然と生きる」【賢人の知恵】", [6, 9, 12, 15, 25], ["3D6+10", "3D6+20", "3D6+30", "3D6+50", "150"]),
  229. 64 => Row.new("老齢のグラントが岩に腰かけ釣りをしている。このイベントが発生するとエネミーは消滅する。「どうだね、よかったら釣り勝負をやっていかないか?」PC全員が行動を消費して3D6を振り、誰かが3か4を出せば見事勝利することができる。「見事じゃ、そこにあるガラクタはワシには必要ないものじゃから好きに持って行くがいい」と財宝を渡してくれる。財宝ランク%sのアイテムを2つ入手可能。", [3, 5, 7, 9, 11]),
  230. 65 => Row.new("沈没した「死者の方舟」だ。探せば何かありそうだが危険そうだ…1D6を振って以下の結果を適用すること。このイベントは無視することができ、その場合は何も起きない。
  231. ----------
  232. 1~2:…これは財宝だ!財宝ランク%sのアイテムと%sを入手。
  233. 3~4:…マストが倒れてきた!「水辺5-3」と同様のイベントが発生する。
  234. 5~6:…船に残っていたアンデッドが襲ってきた!エネミーとエンカウント。", [3, 5, 7, 9, 11], ["スケルトンメイル(鎧)", "死者の心臓(装飾品)", "死霊貴族の服(鎧)", "デュラハンの盾(盾)", "死者の止まらない歯車(装飾品)"]),
  235. 66 => Row.new("貝の群生地だ。貝の中にはキラリと光るものが…あれは真珠だ!行動を消費して[敏捷-%s]判定を行い、成功すれば1回ごとにアイテム「真珠」を入手可能。これは1つ%sGPで売却可能で、4ラウンド目が終了するまで何回でも入手可能。ただし、判定の成否に関わらず〔FP〕を2点消費する。「水中行動」があれば判定不要で〔FP〕も消費しない。有効:【野伏の歩み】", [6, 9, 12, 15, 20], [1000, 2000, 4000, 8000, 20000]),
  236. }
  237. )
  238. 1 forest = EventTable.new(
  239. "森林",
  240. 5,
  241. {
  242. 11 => Row.new("回復の泉。PC全員の〔HP〕〔FP〕が完全に回復する。「★死亡」以外のあらゆるBSも回復する。"),
  243. 12 => Row.new("鬱蒼とした森の奥に見事な佇まいの茶室を見つける。ラウンド中に【ソチャデスカ】を使用した際の回復量が2倍になる。茶室の中には友好的なカラクリフラウがいて、%sGPを支払ったPC全員の〔HP〕〔FP〕を「3D6+%s」点回復してくれる。", [100, 200, 300, 500, 2000], [10, 20, 30, 50, 100]),
  244. 13 => Row.new("おいしそうな果実の木だ!とてもおいしく、食べるとやたらとテンションが高くなる。〔HP〕〔FP〕が「3D6%s」点回復するが、シナリオ終了まで不利な特異点「脳みそ筋肉」を得たかのように猪突猛進型の性格になってしまう。[知力-%s]判定に成功すれば興奮作用のある種をどけてデメリットは受けない。有効:「自然と生きる」【賢人の知恵】", ["", "+5", "+10", "+15", "+30"], [3, 6, 9, 12, 20]),
  245. 14 => Row.new("「ひんやりおいしい森のアイスやさんですよ~。今なら私との握手券付き~♪」フラウが果物いっぱいのトロピカルなアイスクリームを売っている。マジカルクッキング「フラウアイスクリーム」(Lv4)を食べさせてもらえる。この料理の効果は、自分たちが「マジカルクッキング」で作った料理と累積する。"),
  246. 15 => Row.new("森のなかにひっそりとたたずむジンジャを発見して、ナインテイルのカンヌシかミコが旅の無事を祈ってくれる。PT全員に【不死なる炎】がかかり、最終イベントに入るまで、死亡判定に自動成功するようになる。"),
  247. 16 => Row.new("食人植物の花粉による回復の泉の幻影。PTメンバーの〔HP〕〔FP〕のいずれかが減少している場合このイベントは拒否できない。[知力-6]判定に失敗すると食人植物の群生地にふらふらと入り、PC全員が「%s」の「斬撃」属性ダメージを受ける。有利な特異点「自然と生きる」があれば、事前に気が付きダメージは受けない。有効:【賢人の知恵】", ["3D6+20", "3D6+30", "3D6+40", "3D6+60", "150"]),
  248. 21 => Row.new("財宝ランク%sの宝箱を発見する。カギやトラップはかかっていない。行動を消費することで開けることができる。", [0, 2, 4, 6, 8]),
  249. 22 => Row.new("財宝ランク%sの宝箱を発見する。難易度%sのカギがかかっている。行動を消費して[感覚-%s]判定でカギを解除して開けることができる。有効:【盗賊の心得】【ロックスミス】", [1, 3, 5, 7, 9], [3, 6, 9, 12, 20], [3, 6, 9, 12, 20]),
  250. 23 => Row.new("財宝ランク%sの宝箱を発見する。難易度%sのトラップがかかっている。行動を消費して[感覚-%s]判定でトラップを解除して開けることができる。有効:【盗賊の心得】【ロックスミス】", [1, 3, 5, 7, 9], [3, 6, 9, 12, 20], [3, 6, 9, 12, 20]),
  251. 24 => Row.new("上から3本の蔓が垂れ下がっている。すごく引っ張りたくなる形状だ…行動を消費して引っ張ったキャラクターは1D6を振って以下のものを入手する。蔦を1つ引っ張ると他の蔦はスルスルっと上に消えていってしまう。有効:「非凡な直感」
  252. ----------
  253. 1~2:大当たり!財宝ランク%sの財宝
  254. 3~4:小当たり!おいしい果物(%sと同等)
  255. 5~6:「ハズレ」と書かれた硬い木の実が直撃!「%s」点の「打撃」属性ダメージを受ける", [3, 5, 7, 9, 11], ["HPポーション", "高級HPポーション", "最高級HPポーション", "奇跡のポーション", "蘇生ポーション"], ["3D6+10", "3D6+20", "3D6+30", "3D6+50", "150"]),
  256. 25 => Row.new("ミミックの罠。ランダムなキャラクターに「3D+%s」の「斬撃」属性ダメージを与える。[知力-%s]判定に成功すればこの罠を見抜いて無効化でき、なおかつ%sGPを入手可能。有効:【盗賊の心得】【ロックスミス】", [30, 50, 70, 100, 300], [3, 6, 9, 12, 20], [1000, 2000, 5000, 10000, 30000]),
  257. 26 => Row.new("トレジャーイーターの罠。冒険中に入手したアイテム(消耗品・GP以外)を全て失う。[知力-%s]判定に成功すればこの罠を見抜いて無効化することができ、なおかつ%sGP入手可能。", [3, 6, 9, 12, 20], [1000, 2000, 5000, 10000, 30000]),
  258. 31 => Row.new("この獣道を通れば近道になりそうだ!しかし狭くて動きにくい…クリア時の財宝ランクが+1されるが、ラウンド中の〔移動〕に-3のペナルティ。"),
  259. 32 => Row.new("「ホウホウホーウ。そっちの道は危ないぞ…」鳥たちが古い言葉で道案内をしてくれる。[知力-6]判定に成功すれば、クリア時の財宝ランク+1。失敗すると次のイベントは必ず「森林」のエンカウントイベントになる。このイベントが4ラウンド目だった場合、道に迷ってクリア時の財宝ランク-1。有効:「自然と生きる」【賢人の知恵】"),
  260. 33 => Row.new("時計をもった兎が忙しそうに走っている。追いかけていくと木の根本に落っこちて妙な場所についてしまった!4ラウンド目が終了するまで「迷宮オプション」を新たに1つ追加する。このイベントが4ラウンド目だった場合、近道になりクリア時の財宝ランク+1。"),
  261. 34 => Row.new("毒草の群生地だ!突っ切れば近道になりそうだが…気にせず直進すればシナリオ終了まで〔HP〕の最大値と現在値が%s点減少するが、クリア時の財宝ランク+1。迂回すると悪い効果は受けないがクリア時の財宝ランク-1。", [10, 15, 20, 25, 40]),
  262. 35 => Row.new("「花の香りのする方においで」と看板がある。[感覚-%s]判定に失敗すると遠回りになりクリア時の財宝ランク-1。有利な特徴「犬の鼻」が%s", [6, 9, 12, 15, 20], ["あれば判定不要。", "あれば判定不要。", "二段階あれば判定不要。一段階はボーナスのみ。", "二段階あれば判定不要。一段階はボーナスのみ。", "二段階あれば判定不要。一段階はボーナスのみ。"]),
  263. 36 => Row.new("おや、進行方向から動物たちが逃げてくるぞ?…大変だ、森林火災だ!引き返して火災から逃げるとクリア時の財宝ランク-2。構わず突っ切るなら4ラウンド目が終了するまで、ターン開始時に「%s」の「火炎」属性ダメージを受ける。", ["3D6+10", "3D6+15", "3D6+20", "3D6+30", "100"]),
  264. 41 => Row.new("森の盗賊団がこちらの懐を狙ってきた!エネミーとエンカウント。このエネミーからダメージを受けるたびに所持品のうち最も価格の安いものを奪われてしまう。4ラウンド目までに倒せば奪い返すことができる。"),
  265. 42 => Row.new("動物狩りを楽しんでいた魔族と偶然遭遇してしまう。エネミーとエンカウント。「分類:魔物」「分類:魔獣」のエネミーが登場していた場合、魔族たちにに狩られると思い逃亡する。"),
  266. 43 => Row.new("魔族の偵察隊と遭遇する。報告される前に倒さなくては!指定のエネミーを1ラウンド以内に倒せなかった場合、次のエンカウントが発生した際、新たに登場するエネミーは準備万端で待ち構えているため〔先制〕に+10、あらゆる致傷力に+%sのボーナス。", [10, 20, 30, 40, 100]),
  267. 44 => Row.new("森を支配する木の魔族の王に遭遇してしまった!エネミーとエンカウント。%s4ラウンド終了までに討伐に成功すると財宝ランク%sのアイテムを入手できる。", ["エネミーは〔HP〕に+100のボーナス。", "エネミーは〔HP〕に+150のボーナス。", "エネミーは〔HP〕に+200のボーナス。", "", "エネミーは〔HP〕に+200、あらゆる致傷力+200、分類「ネームド」と【始原の力】を追加。"], [3, 5, 7, 9, 11]),
  268. 45 => Row.new("フラウとその尖兵が道案内をしてくれる…と思ったらカラーコンタクトをつけてフラウのふりをした魔族とその尖兵だった!エネミーとエンカウント。尖兵は「PC配置ヘクス」に配置すること。PCはラウンド終了まで〔回避〕に-6のペナルティ。有利な特異点「背中の目」があれば〔回避〕へのペナルティは受けない。"),
  269. 46 => Row.new("迷彩服を着て軍事訓練中の第三師団精鋭コンバット部隊だ!エネミーとエンカウント。エネミーは〔先制〕に+4のボーナス。"),
  270. 51 => Row.new("良い香りが周囲に満ちていく。戦闘中だった場合、闘争心を失わせるキノコの香りで敵味方ともに剣を収め強制的に戦闘終了となる。戦闘中ではなかった場合は[知力-6]判定に失敗すると香りをまともにかいで闘争心を失ってしまい、シナリオ終了まであらゆる致傷力に-5のペナルティ。有効:「犬の鼻」「自然と生きる」【賢人の知恵】"),
  271. 52 => Row.new("突然上から木の蔓が誰かを吊り上げて首を絞めようとする!ランダムなPC1人は[感覚-%s]判定を行い、失敗すると「%s」点の防護点無視ダメージを受け、そのラウンド中は行動も〔回避〕も行えない。有利な特異点「自然と生きる」をもつPCが対象になった場合は何も起きない。有効:【野伏の歩み】", [3, 4, 5, 7, 10], ["3D6+30", "3D6+50", "3D6+70", "3D6+100", "300"]),
  272. 53 => Row.new("巧妙なベアトラップが仕掛けてある。ランダムなキャラクター1人(エネミーも含む)に「%s」点の「斬撃」属性ダメージを与え、〔移動〕〔回避〕を0にする。このトラップにかかったキャラクターか隣接したキャラクターが行動を消費して[感覚-%s]判定に成功すれば解除可能。有効:【盗賊の心得】【ロックスミス】", ["3D6+10", "3D6+20", "3D6+30", "3D6+50", "200"], [6, 8, 10, 12, 20]),
  273. 54 => Row.new("突然前も見えないほどのスコールに見舞われる!敵味方全員の攻撃や【特技】の射程が全て1になってしまう。森林「3-6」の山火事が起きていた場合、鎮火する。"),
  274. 55 => Row.new("ランダムなPC1人が巨大な食虫植物に喰われてしまう!幸いすぐに助け出すことができたのだが、鎧も服もボロボロにされてしまう(イヤーン)喰われたPCが装備していた鎧はシナリオ終了まで使用不可能になる。"),
  275. 56 => Row.new("すさまじい悪臭を放つ巨大な花だ!あまりの悪臭にPCの装備していた「ペット」は全て気絶してシナリオ終了まで使用不可能になる。なぜかギア製のペットももれなく気絶する。有利な得意点「犬の鼻」をもつPCがいれば近寄る前に回避可能。"),
  276. 61 => Row.new("魔族の狩りで傷ついた狼を発見する。ラウンド終了までに〔HP〕を1点でも回復してやればふらふらと歩きだし、木の根元でここを掘れというように吠える。埋まっていたものは1D6を振って決定する。
  277. ----------
  278. 1:犬の糞(ゴミ)
  279. 2:10GP
  280. 3:財宝ランク%sのアイテム
  281. 4:財宝ランク%sのアイテム
  282. 5:財宝ランク%sのアイテム
  283. 6:うぃっしゅすたー(大事なもの)", [0, 2, 4, 6, 8], [1, 3, 5, 7, 9], [2, 4, 6, 8, 10]),
  284. 62 => Row.new("少し開けた原っぱでフラウのダンスパーティーに誘われる。このイベントが発生するとエネミーは消滅する。行動を消費して[敏捷-%s]判定に成功してダンスを踊ると原っぱの中心からすくすくと大きなキノコが育ち、キノコの馬車でダンジョンのゴール付近まで一気にすっとばしてくれる。第4ラウンドが終了したものと扱い、クリア時の財宝ランク+2。", [6, 8, 10, 12, 16]),
  285. 63 => Row.new("フラウたちが「森ガールファッションコンテスト」を開催しており、その助っ人を依頼される。このイベントが発生するとエネミーは消滅する。[意思-%s]判定に成功すれば的確なアドバイスで助っ人を依頼したフラウを優勝に導くことができ、その謝礼として%sを入手できる。", [6, 8, 10, 12, 20], ["狩人の羽根帽子(装飾品)", "緊急召喚の宝珠(装飾品)", "毒の香水瓶(装飾品)", "女王の花冠(装飾品)", "魔将樹のドレス(鎧)"]),
  286. 64 => Row.new("霊樹の花にたまった水が神秘的な魔力を帯びている。[知力-6]判定に成功するとそれにポーションとしての効果があることがわかり、奇跡のポーション(消耗品)を入手する。【ポーションナレッジ】を習得したPCがいれば判定不要。有効:【賢人の知恵】"),
  287. 65 => Row.new("迷子のフラウを見つける。4ラウンド目が終了するまでに他のフラウに出会うイベントが発生した場合、偶然にもそのフラウと知り合いで、お礼に財宝ランク%sのアイテムを渡してくれる。フラウに出会えずシナリオをクリアした場合も、迷宮からひとまず出ることができたお礼に財宝ランク%sのアイテムを渡してくれる。", [3, 5, 7, 9, 11], [1, 3, 5, 7, 9]),
  288. 66 => Row.new("ランダムに選んだPC1人が、うっかり泉に武器を落としてしまう。すると泉から女神が出現して、落とした武器と同じ種類の超高級品の武器(魔将ドロップ品など)を落としたかどうかを聞いてくる。[意思%s]判定に成功すれば正直に答え、武器に%sGPまでの任意のアタッチメントを追加してくれる。失敗すると嘘をついて女神を怒らせてしまい、装備していた武器を失ってしまう。", ["", "-2", "-4", "-6", "-8"], [5000, 10000, 30000, 50000, 100_000]),
  289. }
  290. )
  291. 1 graveyard = EventTable.new(
  292. "墓場",
  293. 6,
  294. {
  295. 11 => Row.new("回復の泉。PC全員の〔HP〕〔FP〕が完全に回復する。「★死亡」以外のあらゆるBSも回復する。"),
  296. 12 => Row.new("「彼らは生前の思いが強すぎ成仏できません。語りかけて鎮めてやるとよいでしょう…」アズマ風の墓石が佇んでいる。[知力-%s]判定か[意思-%s]判定に成功するとアズマ式お祈りや語りかけにより霊に感謝され、〔HP〕〔FP〕とFtが全回復する。失敗すると霊を怒らせて呪われ、全員のFtが1点減少する。有効:【賢人の知恵】(知力)【詩人の交渉術】(意思)", [3, 6, 9, 12, 16], [3, 6, 9, 12, 16]),
  297. 13 => Row.new("墓守の休憩所を見つける。心の落ち着くお線香の香りがする…。〔HP〕〔FP〕%s点とBSを回復する。更にシナリオ終了まで〔抵抗〕に+2のボーナス。", [10, 15, 20, 25, 30]),
  298. 14 => Row.new("「人間か。キミたちはここの亡者のようにならないようにね…」ヒガンバナの世話をするフラウと出会い、「ヒガンバナの毒」を武器に塗ってもらうことができる。物理攻撃の致傷力に+5のボーナス。"),
  299. 15 => Row.new("シルヴァテイルのネクロマンサー達が集まって、何やら怪しい儀式をしている。道中で「★死亡」した、もしくは保険を適用して強制送還されたキャラクターがいれば、〔HP〕〔FP〕とBSが全回復した状態で復活させてもらうことができる。それ以外の場合は不気味な儀式に不安を感じ、FPを1点失う。"),
  300. 16 => Row.new("回復の泉があるのだが…?PCのうち1人でも〔HP〕〔FP〕のいずれかが減少している場合このイベントは拒否できない。PC全員の〔HP〕〔FP〕が完全に回復する。「★死亡」以外のあらゆるBSも回復する。黄泉の国の水を飲んだことでシナリオ終了まで「分類:アンデッド」となり、【死者に鞭】【アマテラスの光】などの、一部の【特技】の効果を受ける。"),
  301. 21 => Row.new("財宝ランク%sの宝箱を発見する。カギやトラップはかかっていない。行動を消費することで開けることができる。", [0, 2, 4, 6, 8]),
  302. 22 => Row.new("財宝ランク%sの宝箱を発見する。難易度%sのカギがかかっている。行動を消費して[感覚-%s]判定でカギを解除して開けることができる。有効:【盗賊の心得】【ロックスミス】", [1, 3, 5, 7, 9], [3, 6, 9, 12, 20], [3, 6, 9, 12, 20]),
  303. 23 => Row.new("財宝ランク%sの宝箱を発見する。難易度%sのトラップがかかっている。行動を消費して[感覚-%s]判定でトラップを解除して開けることができる。有効:【盗賊の心得】【ロックスミス】", [1, 3, 5, 7, 9], [3, 6, 9, 12, 20], [3, 6, 9, 12, 20]),
  304. 24 => Row.new("骸が何かを大事そうに握りしめている(抱きかかえている)。行動を消費して[体力-%s]判定に成功すれば、財宝ランク%sのアイテムを入手できるが、Ftが1点減少する。", [2, 4, 6, 10, 15], [2, 4, 6, 8, 10]),
  305. 25 => Row.new("ミミックの罠。ランダムなキャラクターに「3D+%s」の「斬撃」属性ダメージを与える。[知力-%s]判定に成功すればこの罠を見抜いて無効化でき、なおかつ%sGPを入手可能。有効:【盗賊の心得】【ロックスミス】", [30, 50, 70, 100, 300], [3, 6, 9, 12, 20], [1000, 2000, 5000, 10000, 30000]),
  306. 26 => Row.new("トレジャーイーターの罠。冒険中に入手したアイテム(消耗品・GP以外)を全て失う。[知力-%s]判定に成功すればこの罠を見抜いて無効化することができ、なおかつ%sGP入手可能。", [3, 6, 9, 12, 20], [1000, 2000, 5000, 10000, 30000]),
  307. 31 => Row.new("ちょっとなにか出そうな、柳の木でできたトンネルを発見する。PC全員が[意思]判定を行い、全員成功した場合はクリア時の財宝ランク+1。最も成功度の低かった(失敗度の大きかった)PCは揺れる柳を幽霊と思い込み、4ラウンド終了まであらゆる判定に-2のペナルティ。"),
  308. 32 => Row.new("石畳の道を歩いている途中で朽ちた祠を発見する。何かお供え物をしたほうが良いだろうか?アイテム欄の消耗品1つをお供えすると祠が動いて地下通路が出現する!この通路を通ることで近道できて、クリア時の財宝ランク+1。"),
  309. 33 => Row.new("道が途切れ、草が伸び放題の荒れ地に出る。方向もわからず、進むには骨が折れそうだ…[体力-%s]判定を行い、成功すればクリア時の財宝ランク+1。失敗するとクリア時の財宝ランク-1。", [2, 4, 6, 8, 12]),
  310. 34 => Row.new("どこまでも卒塔婆とススキしかない…同じ景色が続き、進んでいるか怪しくなる。1D6を振って1~3が出れば何もないが、4~6が出るとクリア時の財宝ランク-1。有利な特異点「天体時計」があればペナルティは受けない。"),
  311. 35 => Row.new("地面から突如骨の手が伸びて足を掴んでくる!PC全員が[移動%s]判定を行い、クリア時の財宝ランクが「失敗した人数」分減少する。【死者に鞭】を持つPCがいれば骨は威圧されて引っ込み、この効果は無視できる。", ["+4", "+2", "", "-2", "-5"]),
  312. 36 => Row.new("先へ進む道には纏わりつくような死者の呪いが満ちている。直進するとシナリオ終了まであらゆる判定に-2のペナルティ。遠回りをすると悪影響は受けないがクリア時の財宝ランク-2。【死者に鞭】か【鎮魂の盾】を持つPCがいれば呪いをはねつけ、直進してもペナルティを受けない。"),
  313. 41 => Row.new("墓場に浮かんでいた人魂が突如魔物になって襲いかかってきた!エネミーとエンカウント。エネミーが使用する【狐の送り火】のデータを「疲労:なし」に変更。"),
  314. 42 => Row.new("朽ちていた骨が突如起き上がり襲いかかってきた!エネミーとエンカウント。このエネミーは業物の武器を持っており、物理攻撃の致傷力に+%sのボーナス。", [5, 10, 15, 20, 200]),
  315. 43 => Row.new("不吉な歌を口ずさみ、ステップを踏みながらかわいらしい少女が近づいてくる。エネミーとエンカウント。エネミーの【華劇】はは最初から使用された状態になっており、【華劇】の効果に応じた強化がエネミー全員に適用される。"),
  316. 44 => Row.new("遠くから不吉な進軍の音を聞く。PC全員が[感覚-%s]判定を行い、誰か1人でも成功すれば、第二魔将グレヴディガーの軍勢が迫っているのを知る。全員判定に失敗してしまうとPCは第二魔将グレイヴディガーとその配下である無数の亡霊騎士団と相対することになる。%s有効:「狐の耳」「虫の知らせ」", [2, 4, 6, 8, 10], ["「保険」に入っていなければPCたちは死亡して、グレイヴディガーの配下にさせられてしまう。君たちの冒険はここで終了だ。", "「保険」に入っていなければPCたちは死亡して、グレイヴディガーの配下にさせられてしまう。君たちの冒険はここで終了だ。", "「保険」に入っていなければPCたちは死亡して、グレイヴディガーの配下にさせられてしまう。君たちの冒険はここで終了だ。", "エネミーとエンカウント。", "エネミーとエンカウント(魔将オリジン実装後)。オリジン未実装の場合はイベントの振り直しを行う。"]),
  317. 45 => Row.new("「我らの眠りを妨げるものは誰だ…!」貴族の棺とそれを守る人形だ。墓荒らしには容赦なく襲い掛かる!エネミーとエンカウント。棺の中には貴金属が入っており、一部エネミーの通常ドロップの金額が増加する。"),
  318. 46 => Row.new("壁に埋まった10mはあろうかという巨大な蛇の骨が動き出し襲い掛かってくる!エネミーとエンカウント。"),
  319. 51 => Row.new("PC全員に墓から突然幻影が襲いかかる。幻影なので実害はないのだが、本当の攻撃と思って「パリイ」か「シールド」を1回消費してしまう。どちらも行えない場合、腰を抜かして「☆転倒」を受ける。【トゥルービジョン】などがかかっているPCには無効。"),
  320. 52 => Row.new("「ひひっ、かかったなボケが!」理不尽にもギロチンが突如ランダムなPC1人に落ちてくる!「ドッジ-%s」判定を行い、失敗すると「%s」点の「斬撃」属性ダメージを受ける。", [4, 6, 8, 10, 20], ["3D6+40", "3D6+60", "3D6+80", "3D6+120", "400"]),
  321. 53 => Row.new("「すいっちおーん。私達の仲間にしてやるよ!」用途不明の建物に迷い込んでしまったが…なんてこった、ここは火葬場だ!早く脱出しないと灰になるまで焼かれてしまうぞ!PC全員が「%s」点の「火炎」属性ダメージを受ける。〔移動〕が%s以上のPCは何とか逃げ出しダメージを受けず、さらに自分より[体力]の低いキャラクター1人を連れて脱出可能。有効:【盗賊の心得】【ロックスミス】", ["3D6+30", "3D6+40", "3D6+50", "3D6+70", "300"], [8, 9, 10, 12, 16]),
  322. 54 => Row.new("墓石が動き出し中から何かが出てこようとしている![体力-%s]判定に成功すればなにも起こらないが、失敗すると探索中に倒されたエネミーの中で最もCLが高いエネミーが再度出現する。該当モンスターが存在しなかった場合は、昼寝をしていたフラウが出てくるだけ。", [4, 6, 8, 10, 15]),
  323. 55 => Row.new("金の亡者のゾンビが群がってくる。金を渡してやるまで満足しそうにない…%sGPを支払うと満足して去っていくが、支払いを拒否した場合(もしくはお金が足りなかった場合)はPC全員が「%s」の「打撃」属性ダメージを受ける。【死者に鞭】を持つPCがいればひと睨みでそそくさと去っていく。", [1000, 2000, 4000, 8000, 20000], ["3D6+10", "3D6+20", "3D6+30", "3D6+50", "200"]),
  324. 56 => Row.new("「おやおや。死者に気に入られましたか…困りましたねえホッホッ」ランダムなPC1人の武器が死者の怨念を吸い取り魔剣となる!魔剣は攻撃力に+5のボーナスを得るが、装備していると〔HP〕の最大値が10点減少する。魔剣となった武器は売却不可能で、不要な場合は捨てるしかない。すでに魔剣となっている武器と、【特技】によって入手した武器は魔剣にならない。"),
  325. 61 => Row.new("雷が突然鳴り響く。敵味方全員が3D6を振り、出目が一番高いキャラクターは「%s」点の「電撃」属性ダメージを受ける。", ["3D6+30", "3D6+50", "3D6+70", "3D6+100", "350"]),
  326. 62 => Row.new("「いいところに来たナ。どうだ、お前らも飲んでいくカ?」タルの上に腰かけ、減ることのない酒を口に運び続けるスケルトンがいる。このイベントが発生するとエネミーは消滅する。酒を飲む場合、行動を消費して[意思%s]判定を4回連続で行う。全て成功すると、「ついに酒が切れたカ、最後の晩酌に付き合ってもらって感謝するゼ」と感謝を述べて消滅し、あとには財宝ランク%sのアイテムが残る。途中で1度でも失敗した場合、酒に悪酔いしてシナリオ終了まであらゆる判定に-2のペナルティ。", ["", "-1", "-2", "-4", "-8"], [3, 5, 7, 9, 11]),
  327. 63 => Row.new("怪しい輝きを放つ宝石を発見する。手にとったPCは呪われてシナリオ終了まであらゆる判定に-2のペナルティ。手に取らない場合は全員に[意思%s]判定が必要で、不利な特異点「金の亡者」「好奇心は猫を殺す」があるとこの[意思]判定に-4のペナルティ。無事持ち帰った場合呪いは解け、%sGPで売却できる。", ["", "-1", "-2", "-3", "-6"], [2000, 6000, 20000, 60000, 150_000]),
  328. 64 => Row.new("朽ちたギアの墓場だ。まだ使えるギアがあるかもしれない。【魔導工学のススメ】があれば、SLvに応じたアイテムが1つ入手可能。
  329. ----------
  330. SLv1:カラクリバランサー(装飾品)
  331. SLv2:カラクリお茶キット(装飾品)
  332. SLv3:ゴーレムアーム(装飾品)
  333. %s
  334. %s
  335. %s
  336. %s", ["", "SLv4:ホイールブースター(装飾品)", "SLv4:ホイールブースター(装飾品)", "SLv4:ホイールブースター(装飾品)", "SLv4:ホイールブースター(装飾品)"], ["", "", "SLv5:ナグルファル装甲(装飾品)", "SLv5:ナグルファル装甲(装飾品)", "SLv5:ナグルファル装甲(装飾品)"], ["", "", "", "SLv6:死者の止まらない歯車(装飾品)", "SLv6:死者の止まらない歯車(装飾品)"], ["", "", "", "", "SLv7:特別アタッチメント券(大事なもの)"]),
  337. 65 => Row.new("「ほーらよっといでーよっといでー、地獄の沙汰も金次第…」うすら寒い気配の漂う川辺に出る。川辺には渡し守らしき、ローブをかぶった2人の少女がいる。1人あたり%sGPを支払えばクリア時の財宝ランク+1。支払いを拒否したかお金が足りない場合、エネミーとエンカウント。", [200, 500, 1000, 2000, 5000]),
  338. 66 => Row.new("『千ノ戦イデ千ノ勝チヲ知ル者、ココニ眠ル』と刻まれた棺を見つける。棺を開けた場合はエネミーとエンカウント。勝利すると%sを入手できる。不利な特異点「好奇心は猫を殺す」「脳みそ筋肉」を持つキャラクターは[意思]判定を行い、失敗すると棺を開けてしまう。", ["キメラパーツ(装飾品)", "キメラパーツ(装飾品)", "グレートキメラパーツ(装飾品)", "ウェポンマスターの証(装飾品)", "ウェポンマスターの証(装飾品)"]),
  339. }
  340. )
  341. EVENT_TABLES = [
  342. 1 cave,
  343. ruin,
  344. mountain,
  345. waterside,
  346. forest,
  347. graveyard,
  348. ].freeze
  349. end
  350. end
  351. end

lib/bcdice/game_system/filled_with/lot_tables.rb

94.74% lines covered

100.0% branches covered

19 relevant lines. 18 lines covered and 1 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/dice_table/range_table"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class FilledWith
  6. # ナンバーワンノーマルくじ表(GURPS-FW版)
  7. #
  8. # 別の表に飛ぶ場合は、遅延評価のためにlambdaでジャンプ先の表を括る。
  9. LOT_NORMAL_TABLES = {
  10. 1 1 => DiceTable::RangeTable.new(
  11. "ナンバーワンノーマルくじ(phase 1)",
  12. "1D6",
  13. [
  14. [1..3, "イレブンチキン"],
  15. 2 [4..5, lambda { LOT_NORMAL_TABLES[2] }],
  16. 1 [6, lambda { LOT_NORMAL_TABLES[3] }],
  17. ]
  18. ).freeze,
  19. 2 => DiceTable::RangeTable.new(
  20. "ナンバーワンノーマルくじ(phase 2)",
  21. "1D6",
  22. [
  23. [1, "バロールたわし"],
  24. [2, "イグニスジッポ"],
  25. [3, "ヤコ仮面or梟の文鎮(選択可)"],
  26. [4, "ナレッジのハンモックorジンジャビースト"],
  27. 1 [5..6, lambda { LOT_NORMAL_TABLES[3] }],
  28. ]
  29. ).freeze,
  30. 3 => DiceTable::RangeTable.new(
  31. "ナンバーワンノーマルくじ(phase 3)",
  32. "1D6",
  33. [
  34. [1, "特性HPポーション"],
  35. [2, "特性MPポーション"],
  36. [3, "黒い甲冑"],
  37. [4, "天体望遠鏡"],
  38. [5, "金獅子の剥製"],
  39. 3 [6, lambda { LOT_NORMAL_TABLES[4] }],
  40. ]
  41. ).freeze,
  42. 4 => DiceTable::RangeTable.new(
  43. "ナンバーワンノーマルくじ(phase 4)",
  44. "1D6",
  45. [
  46. [1, "特性スタミナポーション"],
  47. [2, "戦乙女の兜"],
  48. [3, "フェンリルの首輪"],
  49. [4, "フェニックスカーペット"],
  50. [5, "動くアダマンゴーレム"],
  51. 2 [6, lambda { LOT_NORMAL_TABLES[5] }],
  52. ]
  53. ).freeze,
  54. 5 => DiceTable::RangeTable.new(
  55. "ナンバーワンノーマルくじ(phase 5)",
  56. "1D6",
  57. [
  58. [1, "キャンディークッション"],
  59. [2, "屑鉄の金床"],
  60. [3, "薪割り王の斧"],
  61. [4, "ロジエの水差し"],
  62. [5, "箱舟の模型"],
  63. 2 [6, lambda { LOT_PREMIUM_TABLES[5] }],
  64. ]
  65. ).freeze,
  66. }.freeze
  67. # ナンバーワンプレミアムくじ表(GURPS-FW版)
  68. #
  69. # 別の表に飛ぶ場合は、遅延評価のためにlambdaでジャンプ先の表を括る。
  70. LOT_PREMIUM_TABLES = {
  71. 1 1 => DiceTable::RangeTable.new(
  72. "ナンバーワンプレミアムくじ(phase 1)",
  73. "1D6",
  74. [
  75. [1..3, "プレミアムチキン"],
  76. 1 [4, lambda { LOT_NORMAL_TABLES[3] }],
  77. 1 [5..6, lambda { LOT_PREMIUM_TABLES[2] }],
  78. ]
  79. ).freeze,
  80. 2 => DiceTable::RangeTable.new(
  81. "ナンバーワンプレミアムくじ(phase 2)",
  82. "1D6",
  83. [
  84. [1, "親衛隊バッジ"],
  85. [2, "ハタモトチャブダイ"],
  86. [3, "星のコンパス"],
  87. [4, "白銀の甲冑"],
  88. [5, lambda { LOT_NORMAL_TABLES[4] }],
  89. 1 [6, lambda { LOT_PREMIUM_TABLES[3] }],
  90. ]
  91. ).freeze,
  92. 3 => DiceTable::RangeTable.new(
  93. "ナンバーワンプレミアムくじ(phase 3)",
  94. "1D6",
  95. [
  96. [1, "特性クイックHPポーション"],
  97. [2, "特性クイックMPポーション"],
  98. [3, "特製クイックスタミナポーション"],
  99. [4, "火龍のフィギュアor氷龍のフィギュア(選択可)"],
  100. [5, "ヒメショーグンドレス"],
  101. 1 [6, lambda { LOT_PREMIUM_TABLES[4] }],
  102. ]
  103. ).freeze,
  104. 4 => DiceTable::RangeTable.new(
  105. "ナンバーワンプレミアムくじ(phase 4)",
  106. "1D6",
  107. [
  108. [1, "クイックユグドラポーション"],
  109. [2, "銀河龍のフィギュア/ドラゴン"],
  110. [3, "銀河龍のフィギュア/魔族"],
  111. [4, "魔族チェスセット"],
  112. [5, "イグニスコンロ"],
  113. 1 [6, lambda { LOT_PREMIUM_TABLES[5] }],
  114. ]
  115. ).freeze,
  116. 5 => DiceTable::RangeTable.new(
  117. "ナンバーワンプレミアムくじ(phase 5)",
  118. "1D6",
  119. [
  120. [1, "グレヴディバリウス"],
  121. [2, "天使の望遠鏡orデスの目覚まし時計(選択可)"],
  122. [3, "世界樹の蔦"],
  123. [4, "死神の飾りドレス"],
  124. [5, "ザバーニヤ等身大フィギュア"],
  125. 1 [6, lambda { LOT_PREMIUM_TABLES[6] }],
  126. ]
  127. ).freeze,
  128. 6 => DiceTable::RangeTable.new(
  129. "ナンバーワンプレミアムくじ(phase 6)",
  130. "1D6",
  131. [
  132. [1, "イレブンチキン"],
  133. [2, "イレブンチキン(2ピース)"],
  134. [3, "イレブンチキン(3ピース)"],
  135. [4, "イレブンチキン(6ピース)"],
  136. [5, "イレブンチキン(12ピース)"],
  137. [6, "wish star"],
  138. ]
  139. ).freeze,
  140. }.freeze
  141. end
  142. end
  143. end

lib/bcdice/game_system/filled_with/tresure_tables.rb

90.91% lines covered

50.0% branches covered

11 relevant lines. 10 lines covered and 1 lines missed.
2 total branches, 1 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class FilledWith < Base
  5. # 夢幻の迷宮財宝表
  6. 1 def getTresureResult(command)
  7. 6 m = /^TRS(\d+)([+-]\d)?$/.match(command)
  8. 6 else: 6 then: 0 unless m
  9. return nil
  10. end
  11. 6 rank = m[1].to_i + m[2].to_i
  12. 6 rank = rank.clamp(0, 12)
  13. 6 return TRESURE_TABLES[rank].roll(@randomizer)
  14. end
  15. TRESURE_TABLES = {
  16. 1 0 => DiceTable::Table.new(
  17. "財宝表",
  18. "1D6",
  19. [
  20. "HPポーション(消耗品)",
  21. "FPポーション(消耗品)",
  22. "マジックパウダー:火(消耗品)",
  23. "マジックパウダー:氷(消耗品)",
  24. "マジックパウダー:雷(消耗品)",
  25. "500GP",
  26. ]
  27. ),
  28. 1 => DiceTable::Table.new(
  29. "財宝表",
  30. "1D6",
  31. [
  32. "高級HPポーション(消耗品)",
  33. "高級FPポーション(消耗品)",
  34. "高級抵抗ポーション(消耗品)",
  35. "高級鉄壁ポーション(消耗品)",
  36. "マジックパウダー:火、氷、雷の3点セット(消耗品)",
  37. "1000GP",
  38. ]
  39. ),
  40. 2 => DiceTable::Table.new(
  41. "財宝表",
  42. "1D6",
  43. [
  44. "鈴のお守り(装飾品)",
  45. "盗賊の小手(装飾品)",
  46. "狩人の羽帽子(装飾品)",
  47. "狙撃手の指貫(装飾品)",
  48. "「スタミナバンド」「健康お守り」「レザーマント」3点セット",
  49. "2000GP",
  50. ]
  51. ),
  52. 3 => DiceTable::Table.new(
  53. "財宝表",
  54. "1D6",
  55. [
  56. "最高級HPポーション×2(消耗品)",
  57. "最高級FPポーション×2(消耗品)",
  58. "最高級抵抗ポーション×2(消耗品)",
  59. "任意の装飾品1つ(4000GPまでのもの)",
  60. "アタッチメント割引券(全員に1枚)",
  61. "3000GP",
  62. ]
  63. ),
  64. 4 => DiceTable::Table.new(
  65. "財宝表",
  66. "1D6",
  67. [
  68. "任意の「ミスリル」武器1つ",
  69. "ミスリルシールド(盾)",
  70. "ミスリルスケイル(鎧)",
  71. "任意の装飾品1つ(5000GPまでのもの)",
  72. "アタッチメント割引券(全員に2枚)",
  73. "5000GP",
  74. ]
  75. ),
  76. 5 => DiceTable::Table.new(
  77. "財宝表",
  78. "1D6",
  79. [
  80. "任意の武器1つ(10000GPまでのもの)",
  81. "任意の盾1つ(10000GPまでのもの)",
  82. "任意の鎧1つ(10000GPまでのもの)",
  83. "最高級HPポーション(人数分)",
  84. "任意の装飾品1つ(10000GPまでのもの)",
  85. "7500GP",
  86. ]
  87. ),
  88. 6 => DiceTable::Table.new(
  89. "財宝表",
  90. "1D6",
  91. [
  92. "任意の武器1つ(15000GPまでのもの)",
  93. "任意の盾1つ(15000GPまでのもの)",
  94. "任意の鎧1つ(15000GPまでのもの)",
  95. "任意の装飾品1つ(15000GPまでのもの)",
  96. "最高級FPポーション(人数分)",
  97. "10000GP",
  98. ]
  99. ),
  100. 7 => DiceTable::Table.new(
  101. "財宝表",
  102. "1D6",
  103. [
  104. "任意の武器1つ(30000GPまでのもの)",
  105. "任意の盾1つ(30000GPまでのもの)",
  106. "任意の鎧1つ(30000GPまでのもの)",
  107. "任意の装飾品1つ(30000GPまでのもの)",
  108. "蘇生ポーション(消耗品)",
  109. "20000GP",
  110. ]
  111. ),
  112. 8 => DiceTable::Table.new(
  113. "財宝表",
  114. "1D6",
  115. [
  116. "任意の武器1つ(60000GPまでのもの)",
  117. "任意の盾1つ(60000GPまでのもの)",
  118. "任意の鎧1つ(60000GPまでのもの)",
  119. "任意の装飾品1つ(60000GPまでのもの)",
  120. "蘇生ポーション(装飾品)+アタッチメント割引券10枚(割引券は人数分)",
  121. "40000GP",
  122. ]
  123. ),
  124. 9 => DiceTable::Table.new(
  125. "財宝表",
  126. "1D6",
  127. [
  128. "任意の武器1つ(100000GPまでのもの)",
  129. "任意の盾1つ(100000GPまでのもの)",
  130. "任意の鎧1つ(100000GPまでのもの)",
  131. "任意の装飾品1つ(100000GPまでのもの)",
  132. "蘇生ポーション(装飾品)+アタッチメント割引券20枚(割引券は人数分)",
  133. "60000GP",
  134. ]
  135. ),
  136. 10 => DiceTable::Table.new(
  137. "財宝表",
  138. "1D6",
  139. [
  140. "任意の武器1つ(150000GPまでのもの)",
  141. "任意の盾1つ(150000GPまでのもの)",
  142. "任意の鎧1つ(150000GPまでのもの)",
  143. "任意の装飾品1つ(200000GPまでのもの)",
  144. "蘇生ポーション(装飾品)+アタッチメント割引券30枚(割引券は人数分)",
  145. "黄金の守護者の証(装飾品)(【ハッキング】があれば黄金の電子暗号キー(装飾品)も追加)",
  146. ]
  147. ),
  148. 11 => DiceTable::Table.new(
  149. "財宝表",
  150. "1D6",
  151. [
  152. "体力の欠片(大事なもの)(全員に10個)",
  153. "敏捷の欠片(大事なもの)(全員に10個)",
  154. "感覚の欠片(大事なもの)(全員に10個)",
  155. "知力の欠片(大事なもの)(全員に10個)",
  156. "意志の欠片(大事なもの)(全員に10個)",
  157. "お好きな副能力の欠片(大事なもの)(1人ずつ好きなものを選択して全員に50個)",
  158. ]
  159. ),
  160. 12 => DiceTable::Table.new(
  161. "財宝表",
  162. "1D6",
  163. [
  164. "体力の欠片(大事なもの)(全員に20個)",
  165. "敏捷の欠片(大事なもの)(全員に20個)",
  166. "感覚の欠片(大事なもの)(全員に20個)",
  167. "知力の欠片(大事なもの)(全員に20個)",
  168. "意志の欠片(大事なもの)(全員に20個)",
  169. "お好きな副能力の欠片(大事なもの)(1人ずつ好きなものを選択して全員に100個)",
  170. ]
  171. )
  172. }.freeze
  173. end
  174. end
  175. end

lib/bcdice/game_system/kizuna_bullet/tables.rb

100.0% lines covered

100.0% branches covered

54 relevant lines. 54 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class KizunaBullet < Base
  5. 1 class RollTwiceRandomizerTable
  6. 1 def initialize(locale:, a_table:, b_table:)
  7. 6 @locale = locale
  8. 6 @a_table = a_table
  9. 6 @b_table = b_table
  10. end
  11. 1 def roll(randomizer)
  12. 6 results = []
  13. 6 result_a = @a_table.roll(randomizer).to_s
  14. 6 results.push(result_a)
  15. 6 result_b = @b_table.roll(randomizer).to_s
  16. 6 results.push(result_b)
  17. 6 return results.join("\n")
  18. end
  19. end
  20. 1 class Roll4TimesRandomizerTable
  21. 1 def initialize(locale:, a_table:, b_table:, c_table:, d_table:)
  22. 2 @locale = locale
  23. 2 @a_table = a_table
  24. 2 @b_table = b_table
  25. 2 @c_table = c_table
  26. 2 @d_table = d_table
  27. end
  28. 1 def roll(randomizer)
  29. 2 results = []
  30. 2 result_a = @a_table.roll(randomizer).to_s
  31. 2 results.push(result_a)
  32. 2 result_b = @b_table.roll(randomizer).to_s
  33. 2 results.push(result_b)
  34. 2 result_c = @c_table.roll(randomizer).to_s
  35. 2 results.push(result_c)
  36. 2 result_d = @d_table.roll(randomizer).to_s
  37. 2 results.push(result_d)
  38. 2 return results.join("\n")
  39. end
  40. end
  41. 1 class << self
  42. 1 private
  43. 1 def translate_tables(locale)
  44. 1 ordinary_days_place_table = DiceTable::Table.from_i18n("KizunaBullet.table.OP", locale)
  45. 1 ordinary_days_content_table = DiceTable::Table.from_i18n("KizunaBullet.table.OC", locale)
  46. 1 ordinary_days_work_place_table = DiceTable::Table.from_i18n("KizunaBullet.table.OWP", locale)
  47. 1 ordinary_days_work_content_table = DiceTable::Table.from_i18n("KizunaBullet.table.OWC", locale)
  48. 1 ordinary_days_holiday_place_table = DiceTable::Table.from_i18n("KizunaBullet.table.OHP", locale)
  49. 1 ordinary_days_holiday_content_table = DiceTable::Table.from_i18n("KizunaBullet.table.OHC", locale)
  50. 1 ordinary_days_trip_place_table = DiceTable::Table.from_i18n("KizunaBullet.table.OTP", locale)
  51. 1 ordinary_days_trip_content_table = DiceTable::Table.from_i18n("KizunaBullet.table.OTC", locale)
  52. 1 encounter_place_table = DiceTable::Table.from_i18n("KizunaBullet.table.EP", locale)
  53. 1 encounter_order_table = DiceTable::Table.from_i18n("KizunaBullet.table.EO", locale)
  54. 1 encounter_first_table = DiceTable::Table.from_i18n("KizunaBullet.table.EF", locale)
  55. 1 encounter_acquaintance_table = DiceTable::Table.from_i18n("KizunaBullet.table.EA", locale)
  56. 1 encounter_end_table = DiceTable::Table.from_i18n("KizunaBullet.table.EE", locale)
  57. 1 communication_place_table = DiceTable::Table.from_i18n("KizunaBullet.table.CP", locale)
  58. 1 communication_content_table = DiceTable::Table.from_i18n("KizunaBullet.table.CC", locale)
  59. 1 investigation_basic_table = DiceTable::D66Table.from_i18n("KizunaBullet.table.IB", locale)
  60. 1 investigation_dynamic_table = DiceTable::D66Table.from_i18n("KizunaBullet.table.ID", locale)
  61. return {
  62. 1 "OP" => ordinary_days_place_table,
  63. "OC" => ordinary_days_content_table,
  64. "OPC" => RollTwiceRandomizerTable.new(
  65. locale: locale,
  66. a_table: ordinary_days_place_table,
  67. b_table: ordinary_days_content_table
  68. ).freeze,
  69. "OWP" => ordinary_days_work_place_table,
  70. "OWC" => ordinary_days_work_content_table,
  71. "OWPC" => RollTwiceRandomizerTable.new(
  72. locale: locale,
  73. a_table: ordinary_days_work_place_table,
  74. b_table: ordinary_days_work_content_table
  75. ).freeze,
  76. "OHP" => ordinary_days_holiday_place_table,
  77. "OHC" => ordinary_days_holiday_content_table,
  78. "OHPC" => RollTwiceRandomizerTable.new(
  79. locale: locale,
  80. a_table: ordinary_days_holiday_place_table,
  81. b_table: ordinary_days_holiday_content_table
  82. ).freeze,
  83. "OTP" => ordinary_days_trip_place_table,
  84. "OTC" => ordinary_days_trip_content_table,
  85. "OTPC" => RollTwiceRandomizerTable.new(
  86. locale: locale,
  87. a_table: ordinary_days_trip_place_table,
  88. b_table: ordinary_days_trip_content_table
  89. ).freeze,
  90. "TT" => DiceTable::D66Table.from_i18n("KizunaBullet.table.TT", locale),
  91. "TTI" => DiceTable::D66Table.from_i18n("KizunaBullet.table.TTI", locale),
  92. "TTC" => DiceTable::D66Table.from_i18n("KizunaBullet.table.TTC", locale),
  93. "TTH" => DiceTable::D66Table.from_i18n("KizunaBullet.table.TTH", locale),
  94. "EP" => encounter_place_table,
  95. "EO" => encounter_order_table,
  96. "EF" => encounter_first_table,
  97. "EA" => encounter_acquaintance_table,
  98. "EE" => encounter_end_table,
  99. "EFA" => Roll4TimesRandomizerTable.new(
  100. locale: locale,
  101. a_table: encounter_place_table,
  102. b_table: encounter_order_table,
  103. c_table: encounter_first_table,
  104. d_table: encounter_end_table
  105. ).freeze,
  106. "EAA" => Roll4TimesRandomizerTable.new(
  107. locale: locale,
  108. a_table: encounter_place_table,
  109. b_table: encounter_order_table,
  110. c_table: encounter_acquaintance_table,
  111. d_table: encounter_end_table
  112. ).freeze,
  113. "CP" => communication_place_table,
  114. "CC" => communication_content_table,
  115. "CPC" => RollTwiceRandomizerTable.new(
  116. locale: locale,
  117. a_table: communication_place_table,
  118. b_table: communication_content_table
  119. ).freeze,
  120. "IB" => investigation_basic_table,
  121. "ID" => investigation_dynamic_table,
  122. "IBD" => RollTwiceRandomizerTable.new(
  123. locale: locale,
  124. a_table: investigation_basic_table,
  125. b_table: investigation_dynamic_table
  126. ).freeze,
  127. "HA" => DiceTable::Table.from_i18n("KizunaBullet.table.HA", locale),
  128. "NI1" => DiceTable::Table.from_i18n("KizunaBullet.table.NI1", locale),
  129. "NI2" => DiceTable::Table.from_i18n("KizunaBullet.table.NI2", locale),
  130. "NI3" => DiceTable::Table.from_i18n("KizunaBullet.table.NI3", locale),
  131. "NI4" => DiceTable::Table.from_i18n("KizunaBullet.table.NI4", locale),
  132. "NI5" => DiceTable::Table.from_i18n("KizunaBullet.table.NI5", locale),
  133. "NI6" => DiceTable::Table.from_i18n("KizunaBullet.table.NI6", locale),
  134. "NT1" => DiceTable::Table.from_i18n("KizunaBullet.table.NT1", locale),
  135. "NT2" => DiceTable::Table.from_i18n("KizunaBullet.table.NT2", locale),
  136. "NT3" => DiceTable::Table.from_i18n("KizunaBullet.table.NT3", locale),
  137. "NT4" => DiceTable::Table.from_i18n("KizunaBullet.table.NT4", locale),
  138. "NT5" => DiceTable::Table.from_i18n("KizunaBullet.table.NT5", locale),
  139. "NT6" => DiceTable::Table.from_i18n("KizunaBullet.table.NT6", locale),
  140. "HH1" => DiceTable::Table.from_i18n("KizunaBullet.table.HH1", locale),
  141. "HH2" => DiceTable::Table.from_i18n("KizunaBullet.table.HH2", locale),
  142. "HH3" => DiceTable::Table.from_i18n("KizunaBullet.table.HH3", locale),
  143. "HH4" => DiceTable::Table.from_i18n("KizunaBullet.table.HH4", locale),
  144. "HH5" => DiceTable::Table.from_i18n("KizunaBullet.table.HH5", locale),
  145. "HH6" => DiceTable::Table.from_i18n("KizunaBullet.table.HH6", locale),
  146. "HC1" => DiceTable::Table.from_i18n("KizunaBullet.table.HC1", locale),
  147. "HC2" => DiceTable::Table.from_i18n("KizunaBullet.table.HC2", locale),
  148. "HC3" => DiceTable::Table.from_i18n("KizunaBullet.table.HC3", locale),
  149. "HC4" => DiceTable::Table.from_i18n("KizunaBullet.table.HC4", locale),
  150. "HC5" => DiceTable::Table.from_i18n("KizunaBullet.table.HC5", locale),
  151. "HC6" => DiceTable::Table.from_i18n("KizunaBullet.table.HC6", locale),
  152. }.freeze
  153. end
  154. end
  155. end
  156. end
  157. end

lib/bcdice/game_system/meikyu_kingdom/item_table.rb

95.51% lines covered

95.45% branches covered

89 relevant lines. 85 lines covered and 4 lines missed.
22 total branches, 21 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MeikyuKingdom
  5. # デバイスファクトリー(1D6)
  6. 1 def mk_device_factory_table()
  7. 10 output = mk_item_decide_table(@randomizer.roll_once(6))
  8. 10 dice = @randomizer.roll_sum(2, 6)
  9. 10 output = output + " / " + mk_item_features_table(dice)
  10. 10 return output
  11. end
  12. # アイテムカテゴリ決定表(1D6)
  13. 1 def mk_item_decide_table(num)
  14. functionTable = [
  15. 32 [1, lambda { mk_weapon_item_table(@randomizer.roll_d66(D66SortType::ASC)) }],
  16. 5 [2, lambda { mk_life_item_table(@randomizer.roll_d66(D66SortType::ASC)) }],
  17. 3 [3, lambda { mk_rest_item_table(@randomizer.roll_d66(D66SortType::ASC)) }],
  18. 4 [4, lambda { mk_search_item_table(@randomizer.roll_d66(D66SortType::ASC)) }],
  19. 2 [5, lambda { mk_rare_weapon_item_table(@randomizer.roll_d66(D66SortType::NO_SORT)) }],
  20. 4 [6, lambda { mk_rare_item_table(@randomizer.roll_d66(D66SortType::NO_SORT)) }],
  21. ]
  22. 25 return get_table_by_number(num, functionTable)
  23. end
  24. # 武具アイテム表(D66)
  25. 1 def mk_weapon_item_table(num)
  26. table = [
  27. 17 [11, "だんびら"],
  28. [12, "だんびら"],
  29. [13, "ダガー"],
  30. [14, "戦斧"],
  31. [15, "盾"],
  32. [16, "鑓"],
  33. [22, "籠手(だんびら)"],
  34. [23, "手裏剣"],
  35. [24, "石弓"],
  36. [25, "甲冑"],
  37. [26, "戦鎚"],
  38. [33, "大弓(だんびら)"],
  39. [34, "爆弾"],
  40. [35, "鉄砲"],
  41. [36, "大剣"],
  42. [44, "拳銃(だんびら)"],
  43. [45, "ホウキ"],
  44. [46, "徹甲弾"],
  45. [55, "だんびら"],
  46. [56, "大砲"],
  47. [66, "だんびら"],
  48. ]
  49. 17 return get_table_by_number(num, table)
  50. end
  51. # 生活アイテム表(D66)
  52. 1 def mk_life_item_table(num)
  53. table = [
  54. 15 [11, "バックパック"],
  55. [12, "バックパック"],
  56. [13, "鍋"],
  57. [14, "クラッカー"],
  58. [15, "がまぐち"],
  59. [16, "マント"],
  60. [22, "法衣(バックパック)"],
  61. [23, "カード"],
  62. [24, "エプロン"],
  63. [25, "住民台帳"],
  64. [26, "携帯電話"],
  65. [33, "召喚鍵(バックパック)"],
  66. [34, "肖像画"],
  67. [35, "衣装"],
  68. [36, "山吹色のお菓子"],
  69. [44, "バックパック"],
  70. [45, "眼鏡"],
  71. [46, "クレジットカード"],
  72. [55, "バックパック"],
  73. [56, "魔道書"],
  74. [66, "バックパック"],
  75. ]
  76. 15 return get_table_by_number(num, table)
  77. end
  78. # 回復アイテム表(D66)
  79. 1 def mk_rest_item_table(num)
  80. table = [
  81. 13 [11, "お弁当"],
  82. [12, "お弁当"],
  83. [13, "特効薬"],
  84. [14, "保存食"],
  85. [15, "担架"],
  86. [16, "珈琲"],
  87. [22, "軟膏(お弁当)"],
  88. [23, "チョコレート"],
  89. [24, "お酒"],
  90. [25, "フルコース"],
  91. [26, "ポーション"],
  92. [33, "お弁当"],
  93. [34, "救急箱"],
  94. [35, "強壮剤"],
  95. [36, "迷宮保険"],
  96. [44, "お弁当"],
  97. [45, "科学調味料"],
  98. [46, "惚れ薬"],
  99. [55, "お弁当"],
  100. [56, "復活薬"],
  101. [66, "お弁当"],
  102. ]
  103. 13 return get_table_by_number(num, table)
  104. end
  105. # 探索アイテム表(D66)
  106. 1 def mk_search_item_table(num)
  107. table = [
  108. 14 [11, "星の欠片"],
  109. [12, "星の欠片"],
  110. [13, "旗"],
  111. [14, "お守り"],
  112. [15, "拷問具"],
  113. [16, "パワーリスト"],
  114. [22, "工具(星の欠片)"],
  115. [23, "テント"],
  116. [24, "楽器"],
  117. [25, "使い魔"],
  118. [26, "乗騎"],
  119. [33, "迷宮迷彩(星の欠片)"],
  120. [34, "罠百科"],
  121. [35, "迷宮防護服"],
  122. [36, "地図"],
  123. [44, "星の欠片"],
  124. [45, "時計"],
  125. [46, "もぐら棒"],
  126. [55, "星の欠片"],
  127. [56, "カボチャの馬車"],
  128. [66, "星の欠片"],
  129. ]
  130. 14 return get_table_by_number(num, table)
  131. end
  132. # レア武具アイテム表(1D6+1D6)
  133. 1 def mk_rare_weapon_item_table(num)
  134. table = [
  135. 12 [11, "虚弾"],
  136. [12, "怪物毒"],
  137. [13, "小鬼の襟巻"],
  138. [14, "喇叭銃"],
  139. [15, "蛍矢"],
  140. [16, "大盾"],
  141. [21, "まわし"],
  142. [22, "怪物毒"],
  143. [23, "しゃべる剣"],
  144. [24, "小麦粉"],
  145. [25, "王笏"],
  146. [26, "服従の鞭"],
  147. [31, "ぬいぐるみ"],
  148. [32, "魔杖"],
  149. [33, "怪物毒"],
  150. [34, "星衣"],
  151. [35, "聖印"],
  152. [36, "獣の毛皮"],
  153. [41, "日傘"],
  154. [42, "チェインソード"],
  155. [43, "邪眼"],
  156. [44, "怪物毒"],
  157. [45, "徒手空拳"],
  158. [46, "バカには見えない鎧"],
  159. [51, "ビキニアーマー"],
  160. [52, "輝く者"],
  161. [53, "貪る者"],
  162. [54, "滅ぼす者"],
  163. [55, "機械の体"],
  164. [56, "破城槌"],
  165. [61, "刈り取る者"],
  166. [62, "貫く者"],
  167. [63, "黄金の鶴嘴"],
  168. [64, "ムラサマ"],
  169. [65, "蒸気甲冑"],
  170. [66, "王剣"],
  171. ]
  172. 12 return get_table_by_number(num, table)
  173. end
  174. # レア一般アイテム表(1D6+1D6)
  175. 1 def mk_rare_item_table(num)
  176. table = [
  177. 14 [11, "ブルーリボン"],
  178. [12, "聖痕"],
  179. [13, "剥製"],
  180. [14, "愚者の冠"],
  181. [15, "名刺"],
  182. [16, "種籾"],
  183. [21, "香水"],
  184. [22, "守りの指輪(名刺)"],
  185. [23, "煙玉"],
  186. [24, "悪名"],
  187. [25, "藁人形"],
  188. [26, "パワー餌"],
  189. [31, "王妃の鏡"],
  190. [32, "蓄音機"],
  191. [33, "無限の心臓(名刺)"],
  192. [34, "星籠"],
  193. [35, "水晶球"],
  194. [36, "転ばぬ先の杖"],
  195. [41, "悟りの書"],
  196. [42, "操りロープ"],
  197. [43, "盗賊の七つ道具"],
  198. [44, "携帯算術機(名刺)"],
  199. [45, "棺桶"],
  200. [46, "カメラ"],
  201. [51, "不思議なたまご"],
  202. [52, "ブーケ"],
  203. [53, "露眼鏡"],
  204. [54, "災厄王の遺物"],
  205. [55, "経験値"],
  206. [56, "鞍"],
  207. [61, "視肉"],
  208. [62, "玉璽"],
  209. [63, "衛星帯"],
  210. [64, "軍配"],
  211. [65, "聖杯"],
  212. [66, "愛"],
  213. ]
  214. 14 return get_table_by_number(num, table)
  215. end
  216. # アイテムの特性決定表(2D6)
  217. 1 def mk_item_features_table(num)
  218. 34 output = ""
  219. 34 dice = @randomizer.roll_sum(2, 6)
  220. 34 then: 1 if num <= 2
  221. 1 else: 33 output = "「" + mk_item_power_table(@randomizer.roll_once(6)) + "」の神力を宿す"
  222. 33 then: 4 elsif num <= 3
  223. 4 output = "寿命を持つ。寿命の値を決定する。" + "\n"
  224. 4 else: 29 output += "さらに、" + mk_item_features_table(dice)
  225. 29 then: 2 elsif num <= 4
  226. 2 else: 27 output = "境界障壁を持つ。《HP》の値を決定する。"
  227. 27 then: 4 elsif num <= 5
  228. 4 else: 23 output = "銘を持つ。銘を決定する。"
  229. 23 then: 5 elsif num <= 6
  230. 5 else: 18 output = "合成具である。もう1つの機能は「" + mk_item_decide_table(@randomizer.roll_once(6)) + "」である。"
  231. 18 then: 5 elsif num <= 7
  232. 5 output = "そのアイテムにレベルがあれば、レベルを1点上昇する。" + "\n"
  233. 5 else: 13 output += "レベルが設定されていなければ、" + mk_item_features_table(dice)
  234. 13 then: 3 elsif num <= 8
  235. 3 else: 10 output = "「" + mk_item_jyumon_table(dice) + "」の呪紋を持つ。"
  236. 10 then: 4 elsif num <= 9
  237. 4 output = "「" + mk_item_jyuka_table(@randomizer.roll_once(6)) + "」の呪禍を持つ。" + "\n"
  238. 4 else: 6 output += "さらに、" + mk_item_features_table(dice)
  239. 6 then: 4 elsif num <= 10
  240. 4 else: 2 output = "高価だ。価格を設定する。"
  241. 2 then: 1 elsif num <= 11
  242. 1 output = "「条件:" + mk_item_aptitude_table(@randomizer.roll_once(6)) + "」の適性を持つ。" + "\n"
  243. 1 output += "さらに、" + mk_item_features_table(dice)
  244. else: 1 else
  245. 1 output = "「" + mk_item_attribute_table(@randomizer.roll_once(6)) + "」の属性を持つ。"
  246. end
  247. 34 return "特性[" + num.to_s + "]:" + output
  248. end
  249. # 神力決定表(1D6)
  250. 1 def mk_item_power_table(num)
  251. table = [
  252. 1 [1, "〔才覚〕"],
  253. [2, "〔魅力〕"],
  254. [3, "〔探索〕"],
  255. [4, "〔武勇〕"],
  256. [5, "〈器〉"],
  257. [6, "〈回避値〉"],
  258. ]
  259. 1 return "[#{num}]" + get_table_by_number(num, table)
  260. end
  261. # 呪紋決定表(2D6)
  262. 1 def mk_item_jyumon_table(num)
  263. table = [
  264. 3 [2, "モンスタースキル"],
  265. [3, "便利スキル"],
  266. [4, "芸能スキル"],
  267. [5, "迷宮スキル"],
  268. [6, "星術スキル"],
  269. [7, "一般スキル"],
  270. [8, "召喚スキル"],
  271. [9, "科学スキル"],
  272. [10, "交渉スキル"],
  273. [11, "神官のクラススキル"],
  274. [12, "ジョブスキル"],
  275. ]
  276. 3 return "[#{num}]" + get_table_by_number(num, table)
  277. end
  278. # 呪禍表(1D6)
  279. 1 def mk_item_jyuka_table(num)
  280. table = [
  281. 4 [1, "「呪い」のバッドステータス"],
  282. [2, "「肥満」のバッドステータス"],
  283. [3, "「愚か」のバッドステータス"],
  284. [4, "サイクルの終了時に《HP》が1点減少する"],
  285. [5, "条件を満たしても誰とも人間関係を結べない"],
  286. [6, "〈器〉が1点減少する"],
  287. ]
  288. 4 return "[#{num}]" + get_table_by_number(num, table)
  289. end
  290. # 適正表(1D6)
  291. 1 def mk_item_aptitude_table(num)
  292. table = [
  293. 1 [1, "ランダムなクラス1種"],
  294. [2, lambda { mk_family_business_table(@randomizer.roll_d66(D66SortType::ASC)) }],
  295. 1 [3, lambda { mk_gender_table(@randomizer.roll_once(6)) + "性" }],
  296. [4, "上級ジョブ"],
  297. [5, "モンスタースキルを修得"],
  298. [6, "童貞、もしくは処女"],
  299. ]
  300. 1 return "[#{num}]" + get_table_by_number(num, table)
  301. end
  302. # 属性表(1D6)
  303. 1 def mk_item_attribute_table(num)
  304. table = [
  305. 1 [1, "自然の力"],
  306. [2, "幻夢の力"],
  307. [3, "星炎の力"],
  308. [4, "暗黒の力"],
  309. [5, "聖なるの力"],
  310. [6, "災厄の力"],
  311. ]
  312. 1 return "[#{num}]" + get_table_by_number(num, table)
  313. end
  314. 1 def mk_gender_table(num)
  315. 1 output = "1"
  316. 1 then: 0 if num.odd?
  317. output = "男"
  318. else: 1 else
  319. 1 output = "女"
  320. end
  321. 1 return output
  322. end
  323. # 生まれ表(D66)
  324. 1 def mk_family_business_table(num)
  325. table = [
  326. [11, "星術師"],
  327. [12, "魔道師"],
  328. [13, "召喚師"],
  329. [14, "博士"],
  330. [15, "医者"],
  331. [16, "貴族"],
  332. [22, "宦官"],
  333. [23, "武人"],
  334. [24, "処刑人"],
  335. [25, "衛視"],
  336. [26, "商人"],
  337. [33, "迷宮職人"],
  338. [34, "亭主"],
  339. [35, "料理人"],
  340. [36, "寿ぎ屋"],
  341. [44, "働きもの"],
  342. [45, "狩人"],
  343. [46, "冒険者"],
  344. [55, "怠け者"],
  345. [56, "盗賊"],
  346. [66, "生まれ表の中から、好きなジョブ1つを選ぶ"],
  347. ]
  348. return "[#{num}]" + get_table_by_number(num, table)
  349. end
  350. end
  351. end
  352. end

lib/bcdice/game_system/meikyu_kingdom/kingdom_name_table.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MeikyuKingdom
  5. # 王国名決定表1(D66)
  6. 1 def mk_kingdom_name_1_table(num)
  7. table = [
  8. 2 [11, "暗黒"],
  9. [12, "王政"],
  10. [13, "超"],
  11. [14, "共和制"],
  12. [15, "古代"],
  13. [16, "社会主義"],
  14. [22, "自由"],
  15. [23, "新(ネオ)"],
  16. [24, "神聖(セント、聖)"],
  17. [25, "正統"],
  18. [26, "絶対主義"],
  19. [33, "大"],
  20. [34, "天階"],
  21. [35, "深階"],
  22. [36, "第三"],
  23. [44, "中央"],
  24. [45, "帝政"],
  25. [46, "統一"],
  26. [55, "独立"],
  27. [56, "東"],
  28. [66, "立憲"],
  29. ]
  30. 2 return get_table_by_number(num, table)
  31. end
  32. # 王国名決定表2(D66)
  33. 1 def mk_kingdom_name_2_table(num)
  34. table = [
  35. 1 [11, "英雄"],
  36. [12, "連合"],
  37. [13, "グランドゼロ"],
  38. [14, "迷宮(ダンジョン)"],
  39. [15, "災厄"],
  40. [16, "魔神(デーモン)"],
  41. [22, "征服"],
  42. [23, "中華"],
  43. [24, "ドラゴン(龍)"],
  44. [25, "猫"],
  45. [26, "バナナ"],
  46. [33, "ファンタジー"],
  47. [34, "冒険"],
  48. [35, "魔法(マジカル)"],
  49. [36, "超人"],
  50. [44, "無敵"],
  51. [45, "路地裏"],
  52. [46, "ローマ"],
  53. [55, "(好きな単語表で決定)"],
  54. [56, "(プレイ会場の地名 例:ネリマ)"],
  55. [66, "(国王の名前。後で決定)"],
  56. ]
  57. 1 return get_table_by_number(num, table)
  58. end
  59. # 王国名決定表3(D66)
  60. 1 def mk_kingdom_name_3_table(num)
  61. table = [
  62. 1 [11, "王国(キングダム)"],
  63. [12, "王朝"],
  64. [13, "会社(公社)"],
  65. [14, "学園(学校)"],
  66. [15, "合衆国"],
  67. [16, "共同体"],
  68. [22, "共和国"],
  69. [23, "星"],
  70. [24, "公国"],
  71. [25, "市(街、シティ、ポリス)"],
  72. [26, "自治国"],
  73. [33, "植民地"],
  74. [34, "帝国"],
  75. [35, "同盟"],
  76. [36, "首長国"],
  77. [44, "幕府"],
  78. [45, "領"],
  79. [46, "村"],
  80. [55, "横丁(亭)"],
  81. [56, "ランド"],
  82. [66, "連邦"],
  83. ]
  84. 1 return get_table_by_number(num, table)
  85. end
  86. end
  87. end
  88. end

lib/bcdice/game_system/meikyu_kingdom/landscape_table.rb

100.0% lines covered

100.0% branches covered

35 relevant lines. 35 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MeikyuKingdom
  5. # 迷宮風景決定表
  6. 1 def mk_ls_decide_table(num)
  7. 33 output = ""
  8. 33 num.times do |_i|
  9. 132 output += "「" + mk_landscape_table(@randomizer.roll_once(6)) + "」"
  10. end
  11. 33 return output
  12. end
  13. # 迷宮風景表(1D6)
  14. 1 def mk_landscape_table(num)
  15. 132 dice = @randomizer.roll_d66(D66SortType::ASC)
  16. table = [
  17. 153 [1, lambda { mk_artifact_landscape_table(dice) }],
  18. 23 [2, lambda { mk_cave_landscape_table(dice) }],
  19. 19 [3, lambda { mk_natural_landscape_table(dice) }],
  20. 25 [4, lambda { mk_waterside_landscape_table(dice) }],
  21. 28 [5, lambda { mk_skyrealm_landscape_table(dice) }],
  22. 16 [6, lambda { mk_strange_place_landscape_table(dice) }],
  23. ]
  24. 132 return get_table_by_number(num, table)
  25. end
  26. # 人工風景表(D66)
  27. 1 def mk_artifact_landscape_table(num)
  28. table = [
  29. 21 [11, "石組みの部屋"],
  30. [12, "巨大な縦穴に刻まれた螺旋階段"],
  31. [13, "埃だらけの古い図書館"],
  32. [14, "古びた、素朴な祭壇"],
  33. [15, "歯車やピストンがやかましい動力室"],
  34. [16, "石組みの巨大な階段"],
  35. [22, "太い丸太で組まれた部屋"],
  36. [23, "作りかけの製品が放置された工房"],
  37. [24, "錆びた武器や骨が散らばる古戦場"],
  38. [25, "石組みのトイレ"],
  39. [26, "高い天井の厨房"],
  40. [33, "レンガで組まれた部屋"],
  41. [34, "静まりかえった劇場"],
  42. [35, "がらくたが散らばっているゴミ捨て場"],
  43. [36, "切り出し途中で放棄された巨大な石像"],
  44. [44, "壁画やタペストリーが残る大広間"],
  45. [45, "メトロ汗国の線路"],
  46. [46, "絵画や彫刻が展示してあるギャラリー"],
  47. [55, "石棺が並ぶ墓"],
  48. [56, "錆びついた扉が残る巨大な門"],
  49. [66, "放置された牢獄"],
  50. ]
  51. 21 return get_table_by_number(num, table)
  52. end
  53. # 洞窟風景表(D66)
  54. 1 def mk_cave_landscape_table(num)
  55. table = [
  56. 23 [11, "岩肌がむき出しの洞穴"],
  57. [12, "コウモリや羽蟲が飛び交う洞穴"],
  58. [13, "放置された坑道"],
  59. [14, "誰かのキャンプ跡"],
  60. [15, "岩だらけで見通しのきかない空洞"],
  61. [16, "煙が吹きぬける洞穴"],
  62. [22, "どこからか水音が響く鍾乳洞"],
  63. [23, "光の衰えた星がまたたく幻想的な空洞"],
  64. [24, "流砂が流れる洞穴"],
  65. [25, "生物が掘った、つるつるした洞穴"],
  66. [26, "冷えきった氷の洞穴"],
  67. [33, "巨大な岩の隙間"],
  68. [34, "動物や狩を描いた素朴な壁画が続く洞穴"],
  69. [35, "巨大な空洞にかけられた自然の橋"],
  70. [36, "埋まりかけで天井すれすれの洞穴"],
  71. [44, "奈落と断崖絶壁"],
  72. [45, "壁がうごめく蟲でおおわれた洞穴"],
  73. [46, "無数の化石が埋まっている洞穴"],
  74. [55, "熱気を放つ溶岩が流れる空洞"],
  75. [56, "水晶でできた洞穴"],
  76. [66, "骨が散らばるなにものかの住処"],
  77. ]
  78. 23 return get_table_by_number(num, table)
  79. end
  80. # 自然風景表(D66)
  81. 1 def mk_natural_landscape_table(num)
  82. table = [
  83. 19 [11, "苔むした部屋"],
  84. [12, "動物の声が響き渡る密林"],
  85. [13, "つる草でできた通路"],
  86. [14, "空洞いっぱいのお花畑"],
  87. [15, "壁から木の根が突き出している部屋"],
  88. [16, "空洞に広がる耕作地"],
  89. [22, "折り重なって繁茂する森林"],
  90. [23, "垂直の空洞にえんえんと伸びる大木の幹"],
  91. [24, "空洞中に広がるアザラシの営巣地"],
  92. [25, "カビで壁がねとつく部屋"],
  93. [26, "サボテンが点在する部屋"],
  94. [33, "巨大キノコの群生地"],
  95. [34, "真ん中に大木が一本そびえ立っている空洞"],
  96. [35, "通路いっぱいに進む野生ウマトカゲの大群"],
  97. [36, "落ち葉がうずたかく積もった部屋"],
  98. [44, "植え込みで作られた迷宮庭園"],
  99. [45, "生い茂る竹林"],
  100. [46, "松ぼっくりが転がる部屋"],
  101. [55, "丈の長い草が生い茂る部屋"],
  102. [56, "枯れた森林"],
  103. [66, "大木の空洞内のような通路や部屋"],
  104. ]
  105. 19 return get_table_by_number(num, table)
  106. end
  107. # 水域風景表(D66)
  108. 1 def mk_waterside_landscape_table(num)
  109. table = [
  110. 25 [11, "轟々と流れる川にかかった橋"],
  111. [12, "色とりどりの珊瑚の中"],
  112. [13, "腰高まで水に浸かった部屋"],
  113. [14, "澄んだ水が流れる噴水と水飲み場"],
  114. [15, "沸騰する湖"],
  115. [16, "地面が干潟化した部屋"],
  116. [22, "水をたたえた貯水池"],
  117. [23, "熱い蒸気がたちこめる部屋"],
  118. [24, "空洞に広がる沼地"],
  119. [25, "樽や鎖が放置されている船の中"],
  120. [26, "水槽が並ぶ水族館"],
  121. [33, "悪臭を放つ下水道"],
  122. [34, "底に遺跡が見える水没した空洞"],
  123. [35, "桟橋と船着き場"],
  124. [36, "筏やハシケが浮かぶ湖"],
  125. [44, "巨大な縦穴と滝"],
  126. [45, "かつて建設された上水道の中"],
  127. [46, "ペンギンの右往左往する氷結した湖"],
  128. [55, "湯気を立てる温泉"],
  129. [56, "奇怪な彫刻が施された古井戸"],
  130. [66, "壁に貝やフジツボがはりついた部屋"],
  131. ]
  132. 25 return get_table_by_number(num, table)
  133. end
  134. # 天空風景表(D66)
  135. 1 def mk_skyrealm_landscape_table(num)
  136. table = [
  137. 28 [11, "雨が降る部屋"],
  138. [12, "チーズにうがたれた洞穴"],
  139. [13, "中空に何層にも重なる空中庭園"],
  140. [14, "無限に連なる真っ白な洗濯物"],
  141. [15, "天空に向かって伸びる豆の木"],
  142. [16, "巨大な縦穴にぶら下がる縄ばしごや鎖"],
  143. [22, "強風の吹き荒れる部屋"],
  144. [23, "雲の上。なぜか、その上を歩くことができる"],
  145. [24, "濃霧に覆われた空洞"],
  146. [25, "無重量でふわふわ浮く部屋"],
  147. [26, "雪がしんしんと降り積もる部屋"],
  148. [33, "時空がねじ曲がった空中回廊"],
  149. [34, "怪物よけの風車が音を立てる通路"],
  150. [35, "天井に遺跡が見える空洞"],
  151. [36, "轟々と音を立てる巨大排気孔"],
  152. [44, "時折稲妻の走る部屋"],
  153. [45, "鳥の羽毛が舞い落ちる部屋"],
  154. [46, "青空が壁面いっぱいに描かれた空洞"],
  155. [55, "一面、鏡でできた部屋"],
  156. [56, "オーロラがゆらめく空洞"],
  157. [66, "重力方向がばらばらの部屋"],
  158. ]
  159. 28 return get_table_by_number(num, table)
  160. end
  161. # 異界風景表(D66)
  162. 1 def mk_strange_place_landscape_table(num)
  163. table = [
  164. 16 [11, "古びた六畳間"],
  165. [12, "せせこましいカラオケボックス"],
  166. [13, "時の止まった街"],
  167. [14, "ボールが一個転がっている体育館"],
  168. [15, "毛が生えている部屋"],
  169. [16, "なにかの待合室"],
  170. [22, "生物の粘液したたる体内"],
  171. [23, "ブランコやすべり台のある小公園"],
  172. [24, "安っぽいユニットバス"],
  173. [25, "上の住人がうるさい部屋"],
  174. [26, "人骨で組まれている部屋"],
  175. [33, "呼吸している部屋"],
  176. [34, "斜めに傾いた部屋"],
  177. [35, "ラブホテルの一室"],
  178. [36, "ときどきなにかが覗いていく部屋"],
  179. [44, "がやがやと話し声が聞こえる部屋"],
  180. [45, "触手が生えている部屋"],
  181. [46, "机と椅子が置いてある取調室"],
  182. [55, "静まりかえった教室"],
  183. [56, "天井に巨大な人の顔がある部屋"],
  184. [66, "常に揺れている部屋"],
  185. ]
  186. 16 return get_table_by_number(num, table)
  187. end
  188. end
  189. end
  190. end

lib/bcdice/game_system/meikyu_kingdom/name_tables.rb

100.0% lines covered

100.0% branches covered

46 relevant lines. 46 lines covered and 0 lines missed.
12 total branches, 12 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MeikyuKingdom
  5. # 名前表
  6. 1 def mk_name_table
  7. 131 debug("mk_name_table begin")
  8. 131 output = "1"
  9. # 名前表
  10. 131 name_n = @randomizer.roll_once(6)
  11. 131 debug("name_n", name_n)
  12. 131 d1 = @randomizer.roll_d66(D66SortType::ASC)
  13. 131 d2 = @randomizer.roll_d66(D66SortType::ASC)
  14. 131 debug("d1, d2", d1, d2)
  15. 131 debug("name_n", name_n)
  16. 131 if name_n <= 1
  17. then: 21 # 名前表A+二つ名表A
  18. 21 else: 110 output = mk_nick_a_table(mk_name_a_table(d1), d2)
  19. 110 elsif name_n <= 2
  20. then: 27 # 名前表B+二つ名表A
  21. 27 else: 83 output = mk_nick_a_table(mk_name_b_table(d1), d2)
  22. 83 elsif name_n <= 3
  23. then: 20 # 名前表エキゾチック+二つ名表A
  24. 20 else: 63 output = mk_nick_a_table(mk_name_ex_table(d1), d2)
  25. 63 elsif name_n <= 4
  26. then: 26 # 名前表A+二つ名表B
  27. 26 else: 37 output = mk_nick_b_table(mk_name_a_table(d1), d2)
  28. 37 elsif name_n <= 5
  29. then: 20 # 名前表B+二つ名表B
  30. 20 output = mk_nick_b_table(mk_name_b_table(d1), d2)
  31. else
  32. else: 17 # 名前表ファンタジー+二つ名表B
  33. 17 output = mk_nick_b_table(mk_name_fa_table(d1), d2)
  34. end
  35. 131 dice = "#{name_n},#{d1},#{d2}"
  36. 131 return output, dice
  37. end
  38. # 二つ名表A(D66)
  39. 1 def mk_nick_a_table(output, num)
  40. table = [
  41. 68 [11, "“災い転じて福となす”"],
  42. [12, "“七転び八起きの”"],
  43. [13, "“冗談にも程がある”"],
  44. [14, "“虎の尾を踏む”"],
  45. [15, "“石橋を叩いて渡る”"],
  46. [16, "“一を聴いて十を知る”"],
  47. [22, "“喉から手が出る”"],
  48. [23, "“据え膳食わぬは男の恥の”"],
  49. [24, "“天につば吐く”"],
  50. [25, "“風に柳の”"],
  51. [26, "“目に入れても痛くない”"],
  52. [33, "“とかく浮世は色と酒の”"],
  53. [34, "“当たるも八卦、当たらぬも八卦の”"],
  54. [35, "“泣く子も黙る”"],
  55. [36, "“天上天下唯我独尊”"],
  56. [44, "“虫も殺さぬ”"],
  57. [45, "“花も恥じらう”"],
  58. [46, "“触らぬ神に祟り無しの”"],
  59. [55, "“両手に花の”"],
  60. [56, "“(ゲーム会場の地名)でも一、二を争う”"],
  61. ]
  62. 68 then: 67 if num < 66
  63. 67 output = get_table_by_number(num, table) + output
  64. else: 1 else
  65. 1 output = "#{output}#{@randomizer.roll_once(6)}世"
  66. end
  67. 68 return output
  68. end
  69. # 二つ名表B(D66)
  70. 1 def mk_nick_b_table(output, num)
  71. table = [
  72. 63 [11, "“身も蓋もない”"],
  73. [12, "“七人の敵がいる”"],
  74. [13, "“ドラゴンも裸足で逃げ出す”"],
  75. [14, "“われらが”"],
  76. [15, "“機会攻撃を誘発する”"],
  77. [16, "“佳人薄命”"],
  78. [22, "“すねに傷持つ”"],
  79. [23, "“湯上りは親でも惚れる”"],
  80. [24, "“叶わぬ時の神頼みの”"],
  81. [25, "“果報は寝て待つ”"],
  82. [26, "“清濁併せ呑む”"],
  83. [33, "“かゆいところに手が届く”"],
  84. [34, "“酒池肉林の”"],
  85. [35, "“蛇の道は蛇の”"],
  86. [36, "“口から先に生まれた”"],
  87. [44, "“柔よく剛を制す”"],
  88. [45, "“死人に口なしの”"],
  89. [46, "“噂をすれば”"],
  90. [55, "“ミスター/ミス”"],
  91. [56, "“(好きな名前表)の子”"],
  92. [66, "“(好きな単語表)の父/母”"],
  93. ]
  94. 63 return get_table_by_number(num, table) + output
  95. end
  96. # 名前表A(D66)
  97. 1 def mk_name_a_table(num)
  98. table = [
  99. 49 [11, "オレンジ/ジャスミン"],
  100. [12, "ホオズキ/アサガオ"],
  101. [13, "クローバー/ダチュラ"],
  102. [14, "ダフニ/キノコ"],
  103. [15, "グラナーダ/プリムローズ"],
  104. [16, "ラディッシュ/マリーゴールド"],
  105. [22, "サイプレス/マグノリア"],
  106. [23, "バンブー/オリーブ"],
  107. [24, "クラウド/クリマ"],
  108. [25, "タオ/スノウ"],
  109. [26, "アヴァランチ/エクレール"],
  110. [33, "ビバシータ/メトロノーム"],
  111. [34, "カノン/ファゴット"],
  112. [35, "オーボエ/アルモニカ"],
  113. [36, "チューバ/オルガノ"],
  114. [44, "ナン/クッキー"],
  115. [45, "ウイロウ/カシュカシュ"],
  116. [46, "スコーン/クスクス"],
  117. [55, "フラスコ/クリップ"],
  118. [56, "クラパドーラ/クレヨン"],
  119. [66, "ソープ/ブルーム"],
  120. ]
  121. 49 return get_table_by_number(num, table)
  122. end
  123. # 名前表B(D66)
  124. 1 def mk_name_b_table(num)
  125. table = [
  126. 49 [11, "エイジ/ウェンズデイ"],
  127. [12, "ジョルノ/ノエル"],
  128. [13, "タスク/マニャーナ"],
  129. [14, "ウィンター/ジュノー"],
  130. [15, "ハイラン/ブランカ"],
  131. [16, "ウォルナット/ルージュ"],
  132. [22, "グレイ/スカーレット"],
  133. [23, "シュバルツ/モエギ"],
  134. [24, "スロット/キリエ"],
  135. [25, "ジョーカー/ダイス"],
  136. [26, "ジグソウ/ドミノ"],
  137. [33, "バックギャモン/マーブル"],
  138. [34, "シーガロ/ココア"],
  139. [35, "スピーチカ/オレンジペコー"],
  140. [36, "ジッポ/ショコラ"],
  141. [44, "ナインピンズ/ルチャ"],
  142. [45, "デカスロン/ラクロス"],
  143. [46, "カバディ/ピンポン"],
  144. [55, "ポンド/ヴェルベット"],
  145. [56, "ルーブル/コットン"],
  146. [66, "シリング/シルク"],
  147. ]
  148. 49 return get_table_by_number(num, table)
  149. end
  150. # 名前表エキゾチック(D66)
  151. 1 def mk_name_ex_table(num)
  152. table = [
  153. 21 [11, "モアイ/スイショウドクロ"],
  154. [12, "チュパカブラ/ムベンベ"],
  155. [13, "カンフー/インヤン"],
  156. [14, "ブシドー/ミヤコ"],
  157. [15, "チャンピオン/バービー"],
  158. [16, "ウパニシャッド/ゾルゲ"],
  159. [22, "デスマーチ/インテル"],
  160. [23, "ゴッホ/ヴィクトリア"],
  161. [24, "ゾンビ/オニャンコポン"],
  162. [25, "ゲロッパ/カルメン"],
  163. [26, "オーバーキル/サシミ"],
  164. [33, "ブッチャー/デヴィ"],
  165. [34, "ブロンソン/マドンナ"],
  166. [35, "ガイギャックス/エロイカ"],
  167. [36, "好きな星の名前(スピカ,オリオン)"],
  168. [44, "好きな武器の名前(エペ,フランベルジュ)"],
  169. [45, "好きな動物の名前(イタチ,パグ)"],
  170. [46, "好きな鉱物の名前(ルビィ,ヒスイ)"],
  171. [55, "好きな言葉+ドラゴン"],
  172. [56, "好きな単語表で決定する"],
  173. [66, "プレイヤーと同じ名前"],
  174. ]
  175. 21 return get_table_by_number(num, table)
  176. end
  177. # 名前表ファンタジー(D66)
  178. 1 def mk_name_fa_table(num)
  179. table = [
  180. 19 [11, "アダム/イヴ"],
  181. [12, "ジャック/モモ"],
  182. [13, "オズ/アリス"],
  183. [14, "コナン/レダ"],
  184. [15, "アーサー/イシス"],
  185. [16, "エルリック/グローリアーナ"],
  186. [22, "ギルガメッシュ/アマテラス"],
  187. [23, "マハラジャ/クリシュナ"],
  188. [24, "カゲオトコ/クロトカゲ"],
  189. [25, "オルフェウス/ヴィーナス"],
  190. [26, "ソロモン/サロメ"],
  191. [33, "ワタリガラス/ディードリット"],
  192. [34, "ニャルラトホテプ/バースト"],
  193. [35, "アンナタール/フォルトゥナ"],
  194. [36, "ザナドゥ/ヨミ"],
  195. [44, "アルビオン/ラピュタ"],
  196. [45, "ゼンダ/ゴーメンガースト"],
  197. [46, "インスマウス/イース"],
  198. [55, "フウヌイム/ヤプー"],
  199. [56, "ザンス/ナルニア"],
  200. [66, "カレワラ/イーハトーブ"],
  201. ]
  202. 19 return get_table_by_number(num, table)
  203. end
  204. end
  205. end
  206. end
  207. # puts BCDice::GameSystem::MeikyuKingdom.new.methods.sort
  208. # exit 1

lib/bcdice/game_system/meikyu_kingdom/placename_table.rb

100.0% lines covered

100.0% branches covered

43 relevant lines. 43 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MeikyuKingdom
  5. # 地名決定表
  6. 1 def mk_pn_decide_table(num)
  7. 33 output = ""
  8. 33 d1 = @randomizer.roll_once(6)
  9. 33 d2 = @randomizer.roll_once(6)
  10. 33 debug("d1", d1)
  11. 33 debug("d2", d2)
  12. 33 d1 = (d1 / 2.0).ceil.to_i
  13. 33 d2 = (d2 / 2.0).ceil.to_i
  14. 33 num.times do |_i|
  15. 132 output += "「" + mk_decoration_table(d1) + mk_placename_table(d2) + "」"
  16. end
  17. 33 return output
  18. end
  19. # 修飾決定表(1D6)
  20. 1 def mk_decoration_table(num)
  21. 132 debug("mk_decoration_table num", num)
  22. table = [
  23. 191 [1, lambda { mk_basic_decoration_table(@randomizer.roll_d66(D66SortType::ASC)) }],
  24. 17 [2, lambda { mk_spooky_decoration_table(@randomizer.roll_d66(D66SortType::ASC)) }],
  25. 56 [3, lambda { mk_katakana_decoration_table(@randomizer.roll_d66(D66SortType::ASC)) }],
  26. ]
  27. 132 return get_table_by_number(num, table)
  28. end
  29. # 地名決定表(1D6)
  30. 1 def mk_placename_table(num)
  31. table = [
  32. 190 [1, lambda { mk_passage_placename_table(@randomizer.roll_d66(D66SortType::ASC)) }],
  33. 45 [2, lambda { mk_natural_placename_table(@randomizer.roll_d66(D66SortType::ASC)) }],
  34. 29 [3, lambda { mk_artifact_placename_table(@randomizer.roll_d66(D66SortType::ASC)) }],
  35. ]
  36. 132 return get_table_by_number(num, table)
  37. end
  38. # 基本表(D66)
  39. 1 def mk_basic_decoration_table(num)
  40. table = [
  41. 59 [11, "欲望(よくぼう)"],
  42. [12, "漂流(ひょうりゅう)"],
  43. [13, "黄金(おうごん)"],
  44. [14, "火達磨(ひだるま)"],
  45. [15, "災厄(さいやく)"],
  46. [16, "三日月(みかづき)"],
  47. [22, "絡繰り(からくり)"],
  48. [23, "流星(りゅうせい)"],
  49. [24, "棘々(とげとげ)"],
  50. [25, "鏡(かがみ)"],
  51. [26, "銀鱗(ぎんりん)"],
  52. [33, "螺旋(らせん)"],
  53. [34, "七色(なないろ)"],
  54. [35, "殉教(じゅんきょう)"],
  55. [36, "水晶(すいしょう)"],
  56. [44, "氷結(ひょうけつ)"],
  57. [45, "忘却(ぼうきゃく)"],
  58. [46, "幸福(こうふく)"],
  59. [55, "妖精(ようせい)"],
  60. [56, "霧雨(きりさめ)"],
  61. [66, "夕暮れ(ゆうぐれ)"],
  62. ]
  63. 59 return get_table_by_number(num, table)
  64. end
  65. # 不気味表(D66)
  66. 1 def mk_spooky_decoration_table(num)
  67. table = [
  68. 17 [11, "赤錆(あかさび)"],
  69. [12, "串刺し(くしざし)"],
  70. [13, "鬼蜘蛛(おにぐも)"],
  71. [14, "蠍(さそり)"],
  72. [15, "幽霊(ゆうれい)"],
  73. [16, "髑髏(どくろ)"],
  74. [22, "血溜まり(ちだまり)"],
  75. [23, "臓物(ぞうもつ)"],
  76. [24, "骸(むくろ)"],
  77. [25, "鉤爪(かぎづめ)"],
  78. [26, "犬狼(けんろう)"],
  79. [33, "奈落(ならく)"],
  80. [34, "大蛇(おろち)"],
  81. [35, "地獄(じごく)"],
  82. [36, "蚯蚓(みみず)"],
  83. [44, "退廃(たいはい)"],
  84. [45, "土竜(もぐら)"],
  85. [46, "絶望(ぜつぼう)"],
  86. [55, "夜泣き(よなき)"],
  87. [56, "緑林(りょくりん)"],
  88. [66, "どん底(どんぞこ)"],
  89. ]
  90. 17 return get_table_by_number(num, table)
  91. end
  92. # カタカナ表(D66)
  93. 1 def mk_katakana_decoration_table(num)
  94. table = [
  95. 56 [11, "マヨネーズ"],
  96. [12, "ダイナマイト"],
  97. [13, "ドラゴン"],
  98. [14, "ボヨヨン"],
  99. [15, "モケモケ"],
  100. [16, "マヌエル"],
  101. [22, "ダイス"],
  102. [23, "ロマン"],
  103. [24, "ウクレレ"],
  104. [25, "エップカプ"],
  105. [26, "カンパネルラ"],
  106. [33, "マンチキン"],
  107. [34, "バロック"],
  108. [35, "ミサイル"],
  109. [36, "ドッキリ"],
  110. [44, "ブラック"],
  111. [45, "好きなモンスターの名前"],
  112. [46, "好きなトラップの名前"],
  113. [55, "好きな単語表で"],
  114. [56, "好きな名前決定表で"],
  115. [66, "好きな数字の組み合わせ"],
  116. ]
  117. 56 return get_table_by_number(num, table)
  118. end
  119. # 通路系地名表(D66)
  120. 1 def mk_passage_placename_table(num)
  121. table = [
  122. 58 [11, "門(ゲート)"],
  123. [12, "回廊(コリドー)"],
  124. [13, "通り(ストリート)"],
  125. [14, "小路(アレイ)"],
  126. [15, "大路(アベニュー)"],
  127. [16, "街道(ロード)"],
  128. [22, "鉄道(ライン)"],
  129. [23, "迷宮(メイズ)"],
  130. [24, "坑道(トンネル)"],
  131. [25, "坂(スロープ)"],
  132. [26, "峠(パス)"],
  133. [33, "運河(カナル)"],
  134. [34, "水路(チャネル)"],
  135. [35, "河(ストリーム)"],
  136. [36, "堀(モート)"],
  137. [44, "溝(ダイク)"],
  138. [45, "階段(ステア)"],
  139. [46, "辻(トレイル)"],
  140. [55, "橋(ブリッジ)"],
  141. [56, "穴(ホール)"],
  142. [66, "柱廊(ストア)"],
  143. ]
  144. 58 return get_table_by_number(num, table)
  145. end
  146. # 自然系地名表(D66)
  147. 1 def mk_natural_placename_table(num)
  148. table = [
  149. 45 [11, "砂漠(デザート)"],
  150. [12, "丘陵(ヒル)"],
  151. [13, "海(オーシャン)"],
  152. [14, "森(フォレスト)"],
  153. [15, "沼(ポンド)"],
  154. [16, "海岸(コースト)"],
  155. [22, "密林(ジャングル)"],
  156. [23, "湖(レイク)"],
  157. [24, "山脈(マウンテンズ)"],
  158. [25, "平原(プレイン)"],
  159. [26, "ヶ原(ランド)"],
  160. [33, "荒野(ヒース)"],
  161. [34, "渓谷(ヴァレー)"],
  162. [35, "島(アイランド)"],
  163. [36, "連峰(ピークス)"],
  164. [44, "火山(ヴォルケイノ)"],
  165. [45, "湿原(ウェットランド)"],
  166. [46, "星雲(ネビュラ)"],
  167. [55, "星(スター)"],
  168. [56, "ヶ淵(プール)"],
  169. [66, "雪原(スノウズ)"],
  170. ]
  171. 45 return get_table_by_number(num, table)
  172. end
  173. # 人工系地名表(D66)
  174. 1 def mk_artifact_placename_table(num)
  175. table = [
  176. 29 [11, "城(キャッスル)"],
  177. [12, "壁(ウォール)"],
  178. [13, "砦(フォート)"],
  179. [14, "地帯(ゾーン)"],
  180. [15, "室(ルーム)"],
  181. [16, "の間(チャンバー)"],
  182. [22, "浴室(バス)"],
  183. [23, "畑(ファーム)"],
  184. [24, "館(ハウス)"],
  185. [25, "座(コンスティレィション)"],
  186. [26, "遺跡(ルイン)"],
  187. [33, "ヶ浜(ビーチ)"],
  188. [34, "塔(タワー)"],
  189. [35, "墓場(グレイブ)"],
  190. [36, "洞(ケイヴ)"],
  191. [44, "堂(バジリカ)"],
  192. [45, "野(フィールド)"],
  193. [46, "書院(スタディ)"],
  194. [55, "駅前(ステイション)"],
  195. [56, "房(クラスター)"],
  196. [66, "腐海(ケイオスシー)"],
  197. ]
  198. 29 return get_table_by_number(num, table)
  199. end
  200. end
  201. end
  202. end

lib/bcdice/game_system/meikyu_kingdom/tables.rb

100.0% lines covered

100.0% branches covered

87 relevant lines. 87 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MeikyuKingdom
  5. # 生活散策表(2d6)
  6. 1 def mk_life_research_table
  7. 10 get_table_by_2d6([
  8. "ハグルマ資本主義神聖共和国から使者が現れる。受け入れる場合[生活レベル/9]に成功すると(1d6)MG獲得。この判定の難易度は、ハグルマとの関係が険悪なら+2、敵対なら+4される。使者を受け入れない場合、ハグルマとの関係が1段階悪化する。すでに関係が敵対なら、領土1つを失う",
  9. "王国の活気にやる気がでる。《気力》+1、もう一度王国フェイズに行動できる",
  10. "この国の評判を聞いて、旅人がやってくる。このゲームのシナリオの目的を果たしたら、終了フェイズに《民》+(2d6)人",
  11. "旅の商人に出会い、昨今の相場を聞く。(2d6)を振り、メモしておく。終了フェイズの収支報告のタイミングに、2d6を振る代わりにその目が出たことにして相場を決定する",
  12. "主婦たちの井戸端会議によると、生活用品が不足しているらしい。ゲーム中に「革」5個を獲得するたびに《民の声》+1。終了フェイズの収支報告までに1個も「革」を獲得出来ないと、維持費+1MG",
  13. "食料に対する不安を漏らす民の姿を見かける。ゲーム中に「肉」5個を獲得するたびに《民の声》+1。終了フェイズの収支報告までに1個も「肉」を獲得出来ないと、維持費+1MG",
  14. "散策の途中、様々な施設が老朽化しているのを発見する。ゲーム中に「木」5個を獲得するたびに《民の声》+1。終了フェイズの収支報告までに1個も「木」を獲得出来ないと、維持費+1MG",
  15. "お腹の大きくなった女性が、無事戻ったら赤子の名付け親になって欲しいと言う。このゲームのシナリオの目的を果たしたら、終了フェイズに《民》+(2d6)人",
  16. "王国内で民とともに汗を流す。[生活レベル/9]の判定に成功すると、(生産施設の数×1)MGを獲得する",
  17. "「これ、便利だと思うんですけど」 [生活レベル/11]の判定に成功すると、価格が自国の[生活レベル]以下の生活アイテム1個を1Lvで獲得できる",
  18. "突然王国に旅人が訪れ、王国の食料庫が乏しくなってくる。[生活レベル/11]に成功すると、他国から補給を呼んで《民》+(2d6)人。失敗すると《民》-(2d6)人",
  19. ])
  20. end
  21. # 治安散策表(2d6)
  22. 1 def mk_order_research_table
  23. 10 get_table_by_2d6([
  24. "メトロ汗国から使者が現れる。受け入れる場合、[治安レベル/9]に成功すると《民》+(2d6)人。失敗すると《民》-(2d6)人。この判定の難易度は、汗国との関係が険悪なら+2、敵対なら+4される。使者を受け入れない場合、汗国との関係が1段階悪化する。すでに関係が敵対なら、領土1つを失う",
  25. "「つまらないものですが、これを冒険に役立ててください……」相場表でランダムに素材1種を選び、それを(1d6)個獲得する",
  26. "民たちが自分らで、王国を守る相談をしている。この気0無のシナリオの目的を果たしたら、好きなレベルのある施設1軒を選び、その隣の部屋に同じ施設1軒を建設する",
  27. "毎日の散歩の成果が出て、体の調子が良い。このゲーム中、《HP》の最大値+5し、《HP》5点回復する",
  28. "王国の民たちが、ランドメイカーの留守を守る人間が少ないことを心配している。ゲーム中に逸材1人を獲得するたびに《民の声》+1。終了フェイズまでに1人も逸材を獲得出来ないと、維持費+1MG",
  29. "王国周辺の迷宮化が進んでいる。対迷宮化結界を強化せねば…。ゲーム中に「魔素」5個を獲得するたびに《民の声》+1。終了フェイズの収支報告までに1個も「魔素」を獲得出来ないと、維持費+1MG",
  30. "王国内の施設の稼働率が下がっている。整備が必要そうだ。ゲーム中に「機械」5個を獲得するたびに《民の声》+1。終了フェイズの収支報告までに1個も「機械」を獲得出来ないと、維持費+1MG",
  31. "周辺諸国の噂を聞く。王国シートの既知の土地欄の中から、関係が同盟・良好・中立の他国があれば、ランダムに国1つを選ぶ、相場表でランダムに素材1種類を選ぶ。その国の相場はその素材となる",
  32. "王国の平和な光景を見て、手応えを感じる。[治安レベル/9」の判定に成功すると、[公共施設の数×1]MGを獲得する",
  33. "「迷宮のごかごがありますように……」 [治安レベル/11]の判定に成功すると、価格が自国の[生活レベル]以下の探索アイテム1個を1Lvで獲得できる",
  34. "王国の中で不満分子たちがなにやら不穏な話をしているのを耳にする。[治安レベル/11]の判定に成功すると、あなたは留守中の準備をしておくことができる。そのゲーム中、一度だけ王国災厄表の結果を無効にすることができる。失敗すると、ランダムに施設1軒を選び、それが破壊される",
  35. ])
  36. end
  37. # 文化散策表(2d6)
  38. 1 def mk_calture_research_table
  39. 10 get_table_by_2d6([
  40. "千年王朝から使者が現れる。受け入れる場合、[文化レベル/9]に成功すると《民の声》+(1d6)、失敗するとすると《民の声》-(1d6)。この判定の難易度は、千年王朝との関係が険悪なら+2、敵対なら+4される。使者を受け入れない場合、千年王朝との関係が1段階悪化する。すでに関係が敵対なら、領土1つを失う",
  41. "民が祭りの準備を進めている。シナリオの目的を果たしていれば、収支報告の時に[収支報告時の《民の声》-ゲーム開始時の《民の声》]MGを獲得できる。ただし、数値がマイナスになった場合は、その分維持費が上昇する",
  42. "都会に出て行った幼馴染から手紙がくる。王国の様子を知りたがっているようだ。シナリオの目的を果たしたら、終了フェイズにランダムなジョブの逸材1人を獲得する",
  43. "他のランドおメイカーの噂を聞く。宮廷から好きなキャラクター1人を選び、そのキャラクターに対する《好意》+1",
  44. "若者たちの有志が、街を発展させるため諸外国のことを勉強したいと言い出した。ゲーム中に「情報」5個を獲得するたびに《民の声》+1。終了フェイズの収支報告までに1個も「情報」を獲得出来ないと、維持費+1MG",
  45. "若い娘たちが、流行の衣装について楽しそうに話している。ゲーム中に「衣料」5個を獲得するたびに《民の声》+1。終了フェイズの収支報告までに1個も「衣料」を獲得出来ないと、維持費+1MG",
  46. "民たちが、君のうわさ話をしている。ゲーム中にあなたにたいして「恋人」「忠義」「親友」の人間関係が成立するたびに《民の声》+2。終了フェイズの収支報告までに1回も人間関係が成立できないと、維持費+1MG",
  47. "あなたに熱い視線が注がれているのを感じる。宮廷から好きなキャラクター1人を選び、そのキャラクターの自分に対する《好意》+1",
  48. "王国内を訪れる旅人たちを見かける。[文化レベル/9]の判定に成功すると、[憩いの施設の数×1]MGを獲得する",
  49. "「ご無事をお祈りしております……」 [文化レベル/11]の判定に成功すると、価格が自国の[生活レベル]以下の回復アイテム1個を1Lvで獲得できる",
  50. "王国の中の民たちの表情に制裁がない。暗い迷宮生活に倦んでいるようだ。[文化レベル/11]の判定に成功すると民を盛り上げる祭りを開き、《民の声》+(1d6)。失敗すると維持費+(1d6)",
  51. ])
  52. end
  53. # 軍事散策表(2d6)
  54. 1 def mk_army_research_table
  55. 10 get_table_by_2d6([
  56. "ダイナマイト帝国から使者が現れる。受け入れる場合、[軍事レベル/9]に成功すると(1d6)MG獲得、失敗すると維持費+(1d6)MG。この判定の難易度は、ダイナマイトとの関係が険悪なら+2、敵対なら+4される。使者を受け入れない場合、ダイナマイトとの関係が1段階悪化する。すでに関係が敵対なら、領土1つを失う",
  57. "長老から迷宮の昔話を聞く。このゲーム中、自分のレベル以下のモンスターを倒すと、そのモンスターをモンスターの《民》にすることができる。この効果は、そのゲーム中に1度だけ使用できる",
  58. "冒険に向かう君に期待の声がかかる。民たちの期待に、気持ちが引き締まる。このゲーム中、《器》が1点上昇する",
  59. "くだらないことで口論になる。宮廷の中から1人を選び、互いに対する《敵意》+1",
  60. "兵士たちの訓練の様子を見るが、武装がやや乏しい。ゲーム中に「牙」5個を獲得するたびに《民の声》+1。終了フェイズの収支報告までに1個も「牙」を獲得出来ないと、維持費+1MG",
  61. "旅人から隣国が軍備を拡張していると言う噂を聞く。ゲーム中に「鉄」5個を獲得するたびに《民の声》+1。終了フェイズの収支報告までに1個も「鉄」を獲得出来ないと、維持費+1MG",
  62. "近隣で凶悪なモンスターたちが大量発生していると言う。ゲーム中に「火薬」5個を獲得するたびに《民の声》+1。終了フェイズの収支報告までに1個も「火薬」を獲得出来ないと、維持費+1MG",
  63. "周辺諸国で戦争が勃発する。王国シートの既知の土地欄から2つの国を選び、両国間で戦争を行う。それぞれ「領土数+(1d6)」が戦力。大きい方が勝利して領土1つを獲得し、負けた方の国は領土を1つ失う。どちらかに援軍を送ることができる。[軍事レベル/9+戦う相手の領土数]の判定に成功すると戦力+(1d6)。勝敗に関係なく援軍を送った国との関係が1段階友好になり、戦った相手の国との関係が1段階悪化する",
  64. "隣国からの貢物が届く。[軍事レベル/11]の判定に成功すると、収支報告の時に価格の()内の数字が[領土の数×1]以下のレアアイテム1個を獲得する",
  65. "「こんなものを用意してみました」 [軍事レベル/11]の判定に成功すると、価格が自国の[生活レベル]以下の武具アイテム1個を1Lvで獲得できる",
  66. "あなたが他の出発を察知して、何者かが国を襲う![軍事レベル/11]の判定に成功するとあなたが他の武勇に歓声が上がり宮廷全員の気力+(1d6)。失敗すると、宮廷全員の《HP》と《配下》が(1d6)減少する",
  67. ])
  68. end
  69. # 才覚休憩表(2d6)
  70. 1 def mk_talent_break_table
  71. 10 get_table_by_2d6([
  72. "民との会話の中、経費節約のアイデアが沸く。[才覚/11]の判定に成功すると、維持費が(1d6)MG減少する",
  73. "嫌いなものが出てくる夢を見て心寂しくなったところに仲間が来てくれる。好きな宮廷内のキャラクター1人への《好意》+1",
  74. "好きなものの夢を見る。シチュエーションを表現し、幸せそうだと感じるプレイヤーが居たら《気力》+2",
  75. "国に残した家族を心配する民を励ます。[才覚/11]の判定に成功すると、《民の声》+2",
  76. "あらん限りの声を力を込めて檄を飛ばす。[才覚/9]の判定に成功すると、宮廷全員のあなたに対する《好意》の合計だけ、《民の声》が回復する",
  77. "休憩中も休み無く働いていると、配下がお茶を入れてくれる。《民の声》+1",
  78. "今後の冒険について口角泡を飛ばして議論する。好きな宮廷内のキャラクター1人を選び、そのキャラの自分に対する《敵意》を好きなだけ上昇させる。上昇した《敵意》と等しい値だけ《民の声》が回復する",
  79. "たまには料理をしようと思い立つ。【お弁当】か【フルコース】の効果を使用して、食事を取ることが出来る。使用した場合、(1d6)を振る。奇数が出たら料理は美味だった、《民の声》+1。偶数が出たら料理は非道い味になった、宮廷全員のあなたに対する《敵意》+1",
  80. "年若い配下に冒険譚をせがまれる。[才覚/現在の《民の声》の値+3]の判定に成功すると、《民の声》+(1d6)。失敗すると次の1クォーター行動できない",
  81. "迷宮に囚われた人々を見つける。助けたいが、食料がやや心配だ。[才覚/9]の判定に成功すると、自分の《配下》+(1d6)",
  82. "この迷宮は一筋縄ではいかないようだ。今こそ、用意していたアレが役に立つだろう。自分の習得しているスキル1種を未修得にし、同じスキルグループのスキル1種を修得してもよい。この効果は永続する。",
  83. ])
  84. end
  85. # 魅力休憩表(2d6)
  86. 1 def mk_charm_break_table
  87. 10 get_table_by_2d6([
  88. "妖精のワイン倉を発見し、酒盛りが始まる。宮廷全員の《気力》+1。[魅力/9]の判定に失敗すると、あなたは脱ぎ出す。(1d6)を振り、奇数なら宮廷全員のあなたに対する《好意》+1、偶数なら《敵意》+1",
  89. "休憩中、意外な寝言を言ってしまう。自分を除く宮廷全員は自分に対する《好意》と《敵意》を入れ替えることが出来る。また、その属性を自由に変更することができる",
  90. "床の冷たさから、ぬくもりを求めて身体を寄せ合う。あなたに《好意》を持っているキャラの数だけ《気力》と《HP》が回復する",
  91. "こっそり二人で抜け出して良い雰囲気に。その部屋の中に、好きなものが同じキャラが居ればそのキャラ1体を選び、互いに対する《好意》+1",
  92. "星の灯りがあなたの顔をロマンチックに照らし出す。その部屋にいる好きなキャラ1体を選び、[魅力/そのキャラのあなたに対する《好意》+9]の判定に成功すると、そのキャラのあなたに対する《好意》+1",
  93. "あいつと目が合う。[魅力/9]の判定に成功したら、宮廷内からランダムに1体選び、そのキャラから自分への《好意》か、または自分のそのキャラへの《好意》いづれかが+1される",
  94. "うたた寝をしていると誰かが毛布を掛けてくれた。ランダムにキャラを選び、自分のそのキャラへの《好意》+1",
  95. "たき火を囲みながら会話を楽しむ。GMの左隣にいるプレイヤーから順番に、自分のPCが《好意》を持っているキャラ1体を選ぶ。選ばれたキャラは《気力》+1。誰からも選ばれなかったキャラは《気力》-1、ランダムに選んだ宮廷内のキャラへの《敵意》+1",
  96. "着替えを覗かれる。宮廷内からランダムに1体選び、(1d6)を振る。奇数なら大声をだしてしまい宮廷全員のそのキャラに対する《敵意》+1、偶数ならそのキャラとあなたの互いの《好意》+1",
  97. "食べ物の匂いにつられたモンスターと遭遇する。ランダムエンカウント表でモンスターを決定する。[魅力/モンスターの中で最も高いレベル+3]の判定に成功した場合、そのモンスターたちと取引できる。失敗した場合戦闘に突入する",
  98. "ふとした拍子に唇が触れあう。好きなキャラ1体を選ぶ。そのキャラの自分以外への《好意》の合計を全て自分に対する《好意》に加える。その後、自分以外への《好意》を0にする",
  99. ])
  100. end
  101. # 探索休憩表(2d6)
  102. 1 def mk_search_break_table
  103. 10 get_table_by_2d6([
  104. "一休みの前に道具の手入れ。ランダムに自分のアイテムスロット1つを選ぶ。そのスロットにレベルがあるアイテムがあった場合、そのアイテムのレベルが1上がる",
  105. "寝床を探していたらアルコープの奥の宝箱を見つける。[探索/11]の判定に成功したら好きな素材1種類を(1d6)個手に入れる",
  106. "一眠りしたら夢の中で…。[探索/11]の判定に成功したら、好きな部屋のモンスターの名前とトラップの数をGMから教えてもらえる",
  107. "配下が眠りにつき、静寂が訪れると隣の部屋から妙な物音が聞こえてきた。隣接する好きな部屋を選ぶ。[探索/10]の判定に成功すると、その部屋にモンスターがいるかどうか、いる場合はモンスターの種類と数が分かる",
  108. "一休みしようと持ったら、モンスターの墓場を発見した。好きな素材を1種類えらび、宮廷全員のあなたにたいする《好意》の合計に等しい個数だけその素材を入手する",
  109. "この部屋はなぜか落ち着く。もしもその部屋の中にあなたの好きなものがあれば《気力》を(1d6)点回復することができる",
  110. "壁に書かれた奇妙な壁画が、あなたを見つめている気がする…。[探索/9]の判定に成功したら、【エレベータ】を発見する",
  111. "白骨化した先客の死体が見つかる。使えそうな装備はありがたく頂戴しておこう。[探索/11]の判定に成功したら、コモンアイテムのカテゴリの中から好きなものを1つ選び、そのカテゴリのアイテムをランダムで1個手に入れる",
  112. "星の灯りで地図を眺める…部屋の構造からして、この辺りに何かありそうだ。[探索/10]の判定に成功すると、この部屋に仕掛けられたイベント型のトラップを全て発見する",
  113. "休んでいる間にトイレにいきたくなった。[探索/11]の判定に成功すると、迷宮のほころびを見つける。このゲームの間、この部屋から迷宮の外へ帰還することができる",
  114. "こ、これは秘密の扉?[探索/11]の判定に成功すると、この部屋に隣接する好きな部屋に通路を延ばすことができる",
  115. ])
  116. end
  117. # 武勇休憩表(2d6)
  118. 1 def mk_valor_break_table
  119. 10 get_table_by_2d6([
  120. "時が満ちるにつれ、闘志が高まる。現在の経過ターン数と等しい数だけ《気力》が回復する",
  121. "もっと敵と戦いたい、血に飢えた自分を発見する。[武勇/11]の判定に成功すると《気力》が1点、《HP》が(1d6)点回復する",
  122. "部屋の片隅にうち捨てられた亡骸を発見する。このマップの支配者の名前が分かっていれば、宮廷全員は支配者への《敵意》を1点上昇させることができる",
  123. "部屋の隅に隠れていた怪物が襲いかかってきた。[武勇/10]の判定に成功すると怪物を追い払い《民の声》+1。失敗すると自分の《配下》-(1d6)、《民の声》-1",
  124. "あいつの短剣がきみの横をかすめて毒蛇を追い払う。好きなキャラ1体を選び、そのキャラに対する《敵意》の分だけ《好意》を上昇させ、その後《敵意》を0にする",
  125. "実力を付けてきたアイツへとドス黒い気持ちがわき上がる。好きなキャラ1体を選び、そのキャラへの《敵意》+1",
  126. "ちょっとした行き違いから軽い口論になる。宮廷内からランダムにキャラ1体を選び、そのキャラとあなたの互いへの《敵意》+1",
  127. "ライバルの活躍が気になる。宮廷全員の中で、最も高いあなたに対する《敵意》の値と同じ数だけ《気力》を獲得する",
  128. "休むべきときにしっかり休む。《HP》を(2d6)点回復することができる",
  129. "怪物のいた痕跡を発見する。[武勇/11]の判定を行い、成功するとGMからこのゲームで遭遇する予定の、まだ種類の分かっていないモンスターを1種類教えてもらえる",
  130. "殺気に反応し飛び起きた!ランダムエンカウント表でモンスターを決定し戦闘を行う。そのモンスターを倒した後、ランダムにレアアイテム1個を手に入れる",
  131. ])
  132. end
  133. # お祭り休憩表(2D6)
  134. 1 def mk_festival_break_table
  135. 10 get_table_by_2d6([
  136. "お祭りに向かう旅人たちとすれ違う。1D6MGが手に入る【宿屋】か【夜店】があれば、さらにもう1D6MGが手に入る",
  137. "なんでこんなときに、ダンジョンに行かなきゃいけないんだ! 「あ、電報でーす」このマップの支配者から、お祭りによせて祝辞の電報がやってくる。そうか、おまえのせいかッ!! マップの支配者の名前が分かり、そのキャラクターへの《敵意》が1D6点上がる",
  138. "「そういえば、国のみんなが何かいってたなぁ……」回想シーン。好きな散策表を1つ選び、2D6を振る。表に照らし合わせた結果を処理する",
  139. "あー。早く帰って、お祭りを楽しみたーい! この時点でキャンプを終了し、すぐに次の部屋へ移動すれば、このクォーターは、時間の経過が起こらない",
  140. "どこからか美味しそうな匂いが漂ってくる。「あ、うまそう」死んだふりをしていた民が起き上がる。今回の冒険で消費していた《配下》が1D6人回復する",
  141. "雰囲気がいつもと違うせいかな。なんかあの人がステキに見える。好きなキャラクター1人を選ぶ。そのキャラクターへの《好意》を1点上げる",
  142. "あ、こんなところにまで屋台が! あてくじ屋さんだ。1MG減らして、好きなアイテムカテゴリを選び、さらにそのカテゴリの中からランダムにアイテム1個を選ぶ。そのアイテムをもらえる(レアアイテムは飾ってあるが、絶対当たらない)",
  143. "お祭りを目指す交易商人と出会う。「あ、王様。これから王国行くんすよ」宮廷の持つ好きな素材を何個でも、同じ数の別の素材と交換してくれる",
  144. "せっかくお祭りなんだし、肩肘はってないで、ノリノリでGO!! このゲーム中は食事をするたびに《民の声》が1点回復する",
  145. "「あ、この歌は……」祭囃子がキミの封印されていたモンスターにまつわる過去の記憶を呼び戻す。好きなモンスター1種類を選ぶ。そのモンスター全般への《敵意》が1点上がる",
  146. "みんなのワクワクがアイテムに乗り移った? ランダムに自分のアイテムスロット1つを選ぶ。そこにレベルのあるアイテムがあった場合、そのレベルが1上がる",
  147. ])
  148. end
  149. # お祭り表(2D6)
  150. 1 def mk_festival_table
  151. 10 get_table_by_2d6([
  152. "祈願祭。国や重要人物の無病息災を祈ったり、戦いの勝利などを祈る祭り。災害や飢饉、流行り病が起こった付近で行われる。シナリオの目的をクリアしていれば、《民》が1D6人上昇する",
  153. "血祭り。戦いに向け、士気を向上させる祭り。戦争だけでなく、迷宮探索に向けて行われることも多い。生贄の血を軍神に捧げたりする。このゲームの間、戦闘に勝利すると《民の声》を1点獲得し、逃走すると《民の声》が1点失われる",
  154. "記念日。建国記念日や領土獲得などの記念日のお祝い。簡単につくることができるが、気がつくと記念日だらけで、何の記念だったかを忘れてしまう。ほどほどに。このゲームの間、行為判定の目で3でも絶対失敗、11でも絶対成功になる(「呪い」のバッドステータスを受けたものは4でも絶対失敗、【必殺】を使った命中判定なら10でも絶対成功)",
  155. "星祭。季節のお祭り。冬至や夏至などの祭りや、七夕、お花見、雪祭りなどが含まれる。季節感の少ない迷宮では、殊更にその風情を楽しもうとやたら盛り上がる。宮廷全員、好きなキャラクター1人を選び、そのキャラクターに対する《好意》を1点上げる",
  156. "民衆の宴。民が自発的に開くお祭り、イベント。アキハバラ電気祭りに餃子祭り、コミックマーケットなど、文化や地域の活性化と結びつくものが多い。このゲームの間、好きな施設1つを選んで、その施設の施設レベルを1上げる",
  157. "誕生日。ランドメイカーや逸材、国の重要人物の誕生日。聖誕祭や花祭りなど、国教の聖人などを祝う国も多い。現王の誕生日を「父の日」、后の誕生日を「母の日」とする国も多い。そのゲームの間、ケーキやおにぎり、缶ジュースなど、1人分が明確な食べ物を食べきったとき、自分のPCが《気力》1点を獲得する",
  158. "冠婚葬祭。国の重要人物の元服(成人)、婚礼、葬儀、祖先の慰霊などの儀式。格式の高い王国では、もっとも重要な祭礼である。このゲームの間、国力を使った判定の達成値を1上昇させる",
  159. "感謝祭。豊漁や豊作などがあったときに自然(迷宮)や精霊、信仰対象など、偉大なるものへの感謝を捧げるお祭り。獲物の毛の一部を切りとって迷宮に感謝する毛祭りや瀬祭り、豊饒を祝う新嘗祭などがある。終了フェイズに「木」や「革」、「肉」のいずれかを1つ消費すると、王国変動表の結果を±1の範囲でずらすことができる",
  160. "鬼祭り。お正月に旧年の悪を正す修正会、豆をまいて福を呼び込む追儺の儀式、怪物に仮装した子供たちが夜の王国をねり歩くハロウィーンなど、悪魔や悪霊を払うお祭り。モンスター除けに行われる。このゲームの間、ランダムエンカウントの戦闘後に使用するお宝表が1段階、高いレベルのものを使用する",
  161. "舞踏会。最高の音楽と芸術的な食事、そしてとびきりの衣装で臨む社交界の華。身分や素性を隠してパートナーを探す仮面舞踏会も人気は高い。ちなみに仮面舞踏会では、女性の側から男性をダンスに誘うのが礼儀だぞ。宮廷全員、ランダムにキャラクター1人を選び、そのキャラクターに対する《好意》を1点上げる",
  162. "競技会。国をあげて、スポーツや芸術、ゲームなど、さまざまなジャンルの一番を決めるお祭り、大会。オリンピックや料理勝負、歌合戦などがある。ランダムに能力値1つを選び、宮廷全員で難易度15の判定を行う。このとき成功した中で、もっとも達成値が高かったキャラクターは、シナリオ終了後、終了フェイズの探索会議で決定されるキャラクターとは別に、勲章を得る",
  163. ])
  164. end
  165. # 王国災厄表(2d6)
  166. 1 def mk_kingdom_disaster_table
  167. 10 get_table_by_2d6([
  168. "王国の悪い噂が蔓延する。既知の土地にある他国との関係が全て1段階悪化する",
  169. "自国のモンスターが凶暴化する。自国のモンスターの《民》からランダムに1種類選び、そのレベルと等しいだけ《民》が減少する。その後、その種類のモンスターの《民》は全ていなくなる",
  170. "疫病が大流行する。《民》-(2d6)",
  171. "自国の迷宮化が進行する。自国の領土のマップ数と等しい値だけ維持費が上昇する",
  172. "敵国のテロが横行する。[治安レベル/敵対国数×2+険悪国数+9]の判定に失敗すると、ランダムに施設を1軒失う",
  173. "敵国襲来![軍事レベル/敵対国数×2+険悪国数+9]の判定に失敗すると、ランダムに自国の領土を1つ失う",
  174. "敵国の陰謀。[文化レベル/敵対国数×2+険悪国数+9]の判定に失敗すると、ランダムに逸材を1人失う",
  175. "食糧危機。《民》-(2d6)。王国にある「肉」の素材を1個消費する度に、《民》の減少を1人抑えることができる",
  176. "住民の不満が爆発する。[生活レベル/敵対国数×2+険悪国数+9]の判定に失敗すると《民の声》-1",
  177. "局地的な迷宮津波が発生。ランダムに自国の領土1つを選び、既知の土地の中からランダムに選んだ場所と場所を入れ替える",
  178. "敵国の勢力が強大化する。GMは、関係が敵対の国全てについて、その国の領土に接する土地を1つ選び、その土地をその国の領土にする",
  179. ])
  180. end
  181. # 才覚ハプニング表(2d6)
  182. 1 def mk_talent_happening_table
  183. 10 get_table_by_2d6([
  184. "自分に王国を導くことなどできるのだろうか…。【お酒】を消費することができなければ、このゲーム中[才覚]-1",
  185. "国王の威信が問われる。(2d6)を振り、その値が[《民の声》+宮廷全員の国王に対する《好意》の合計]以上の場合、《民の声》-(1d6)し、さらに才覚ハプニング表を振る",
  186. "思考に霧の帳が降りる。「散漫」のバッドステータスを受ける",
  187. "重大な裏切りを犯してしまう。あなたに対する《好意》が最も高いキャラを1人選ぶ。そのキャラに対する《好意》の分だけそのキャラへの《敵意》を上昇させ、その後《好意》を0にする",
  188. "この人についていっていいのだろうか…?宮廷全員のあなたに対する《好意》-1(最低0)。その結果、誰かの《好意》が0になると《民の声》-1",
  189. "宮廷のスキャンダルが暴露される。宮廷全員のあなたに対する《敵意》のうち最も高いものと同じだけ《民の声》が減少する",
  190. "あなたの失策が噂になる。近隣の国の中からランダムで1つ選ぶ。その国との関係が1段階悪化する",
  191. "王国の経済に破綻の危機が。[生活レベル/9+現在の経過ターン数]の判定に失敗すると維持費+(1d6)MG",
  192. "この区画一体の迷宮化が激しくなる。1クォーターが経過する",
  193. "逸材の賃上げ要求が始まる。終了フェイズの予算会議の時、[今回使用した逸材の数×1]MGだけ維持費が上昇する",
  194. "今の自分に自信が持てなくなる。生まれ表からランダムにジョブを1つ選び、現在のジョブをそのジョブに変更する",
  195. ])
  196. end
  197. # 魅力ハプニング表(2d6)
  198. 1 def mk_charm_happening_table
  199. 10 get_table_by_2d6([
  200. "民同士の諍いに心を痛め、頭髪にもダメージが!【お酒】を消費することができなければ、このゲーム中[魅力]-1",
  201. "何気ない一言が不和の種に…。好きなキャラ1人を選び、宮廷全員のそのキャラに対する《敵意》+1",
  202. "あなたの美しさに嫉妬した迷宮が、あなたの姿を変える。「呪い」のバッドステータスを受ける",
  203. "かわいさ余って憎さ百倍。あなたに対する《好意》が最も高いキャラを1人選ぶ。そのキャラに対する《好意》の分だけそのキャラへの《敵意》を上昇させ、その後《好意》を0にする",
  204. "あなたを巡って不穏な空気が。宮廷全員のあなたに対する「愛情」の《好意》を比べ、高い順に2人選ぶ。その2人の互いに対する《敵意》+1",
  205. "いがみ合う宮廷を見て民の士気が減少する。宮廷全員のあなたに対する《敵意》の中で最も高い値と同じだけ《配下》が減少する",
  206. "宮廷に嫉妬の嵐が巻き起こる。宮廷の中で、あなたに対して愛情を持つキャラクターの数を数える。このゲームの間、行為判定を行うとき、ダイス目の合計がこの値以下なら絶対失敗となる(最低2)",
  207. "愛想を尽かされる。宮廷全員のあなたに対する《好意》-1(最低0)",
  208. "あなたの指揮に疑問の声が。[魅力/自分の《配下》の数]の判定に失敗すると[難易度-達成値]人だけ《配下》が減少する",
  209. "あなたの恋人だという異性が現れる。宮廷全員のあなたに対する《好意》を比べ、最も高いキャラ1人を選ぶ。あなたはそのキャラの[武勇]と同じだけ《HP》を減少させる",
  210. "他人が信用できなくなる。このゲームの間、協調行動を行えなくなり、人間関係のルールも使用できなくなる",
  211. ])
  212. end
  213. # 探索ハプニング表(2d6)
  214. 1 def mk_search_happening_table
  215. 10 get_table_by_2d6([
  216. "指の震えが止まらない。【お酒】を消費することができなければ、このゲーム中[探索]-1",
  217. "流れ星に直撃。《HP》-(1d6)",
  218. "敵の過去を知り、同情してしまう。あなたのこのマップの支配者に対する《好意》+1。このゲームの間、《好意》を持ったキャラに対して攻撃を行い、絶対失敗した場合そのキャラへの《好意》と同じだけ《気力》が減少する",
  219. "昨日の友は今日の敵。あなたに対する《好意》が最も高いキャラを1人選ぶ。そのキャラに対する《好意》の分だけそのキャラへの《敵意》を上昇させ、その後《好意》を0にする",
  220. "うっかりアイテムを落として壊す。ランダムにアイテムスロットを1つ選び、そこにアイテムが入っていればそれを全て破壊する",
  221. "カーネルが活性化しトラップが強化される。このゲームの間、トラップを解除するための難易度+1",
  222. "友情にヒビが!宮廷全員のあなたに対する《好意》-1(最低0)、《敵意》+1",
  223. "敵の迷宮化攻撃!宮廷全員は[探索/11]を行い、失敗したキャラは(2d6)点のダメージを受ける",
  224. "つい出来心から国費に手を出してしまう。GMは好きなコモンアイテム1つを選ぶ。あなたはそのアイテムを手に入れるが、維持費+(1d6)MG、《民の声》-1。同じ部屋のPCは《希望》1点を消費して[探索/9]の判定に成功すれば、それを止めることができる",
  225. "封印されていたトラップを発動させてしまう。ランダムに災害系トラップから1つを選び、それを発動させる",
  226. "あなたを憎む迷宮支配者が賞金をかけた。このゲームの間、モンスターの攻撃やトラップの目標をランダムに決める場合、その目標はかならずあなたになる。(この効果を複数人が受けた場合、その中からランダムで決定する)",
  227. ])
  228. end
  229. # 武勇ハプニング表(2d6)
  230. 1 def mk_valor_happening_table
  231. 10 get_table_by_2d6([
  232. "つい幼児退行を起こしそうになる。【お酒】を消費することができなければ、このゲーム中[武勇]-1",
  233. "不意打ちを食らう。ランダムエンカウントが発生し、奇襲扱いで戦闘を行う",
  234. "配下の期待が、あなたの重荷となる。[現在の《民の声》-(1d6)]だけ《気力》が減少する",
  235. "配下があなたをかばう。自分の《配下》が(1d6)人減少する",
  236. "ムカついたので思わず殴る。自分の《敵意》が最も高いキャラからランダムに1体選び、そのキャラの《HP》が自分の[武勇]と同じだけ減少する",
  237. "決闘だっ!宮廷全員のあなたに対する《敵意》の中で、最も高い値と同じだけあなたの《HP》が減少する",
  238. "豚どもめ…。宮廷全員に対する《敵意》+1",
  239. "古傷が痛み出す。このゲームの間、戦闘で、あなたに対する敵の攻撃が成功すると、常に余分に1点ダメージを受ける",
  240. "不意に絶望と虚無感が襲い、心が折れる。宮廷全員の《気力》-1",
  241. "あなたを親の敵と名乗るものたちが現れた。このゲーム中に倒したモンスターからランダムに1種類を選び、そのモンスター(1d6)体と戦闘を行う",
  242. "自分の失敗が許せない。このゲームの間、《器》が1点減少したものとして扱う",
  243. ])
  244. end
  245. # 王国変動表(2d6)
  246. 1 def mk_kingdom_change_table
  247. 10 get_table_by_2d6([
  248. "列強のプロパガンダが現れる。(1d6)を振り、その目が現在の《民の声》以下で、現在列強の属国になっていたら属国から抜けることができる。上回っていたら、ランダムに列強を1つ選びその属国になる",
  249. "冒険の成功を祝う民たちが出迎えてくれる。《民の声》+2。この結果を出したプレイヤー(以下、当PL)以外の全員は、今回の冒険を振り返り当PLのPCが《好意》を得るとしたら誰が一番ふさわしいかを協議する。決定したキャラへの当PLのPCの《好意》+1",
  250. "何者かによる唐突な奇襲攻撃。未知の土地に面している領土からランダムに1つを選ぶ。[軍事レベル/敵対国数×2+険悪国数+9]の判定に成功すると返り討ちにして(1d6)MGを得る。失敗するとその領土は施設ごと失われる",
  251. "民の労働の結果が明らかに。[生活レベル/敵対国数×2+険悪国数+9]の判定に成功すると《予算》が自国の領土のマップ数と同じだけ増える。失敗したら《予算》が同じだけ減る",
  252. "民は領土を渇望していた。5MGを支払えば、隣接する未知の土地1つを領土にできる。(1d6)を振り、その数だけ通路を引くことができる。通路でつながっていない部屋は自国の領土として扱わない",
  253. "王国の子どもたちがあなた方を見て成長する。《民》が[王国に残した《民》の数÷10+治安レベル]人増える",
  254. "あなたの活躍を耳にした者たちがやってくる。シナリオの目的を満たしている場合、関係が良好・同盟の国の数だけ(1d6)を振り、[合計値+治安レベル]人だけ《民》が増える",
  255. "街の機能に異変が!?[治安レベル/敵対国数×2+険悪国数+9]の判定に成功すると、自国の好きな施設1軒を選び、その施設の隣でかつ通路がつながっている部屋に同じ種類の施設がもう1軒できる。失敗したら、自国のタイプ:部屋の施設を1軒選び、破壊する",
  256. "王国同士の交流が行われた。[文化レベル/敵対国数×2+険悪国数+9]の判定に成功すると、生まれ表でランダムにジョブを決めた逸材が1人増え、好きな国1つとの関係を1段階良好にする。失敗すると、自国の逸材1人を選んで失い、ランダムに決めた国1つとの関係が1段階悪化する",
  257. "ただ、無為に時が過ぎていたわけではない。迷宮フェイズで過ごした1ターンにつき《予算》が1MG増える",
  258. "民の意識が大きく揺れる。(1d6)を振り、その目が現在の《民の声》以下だったら、好きな国力が1点上昇する。上回っていたら、好きな国力が1点減少する",
  259. ])
  260. end
  261. # 王国変動失敗表(2d6)
  262. 1 def mk_kingdom_mischange_table
  263. 10 get_table_by_2d6([
  264. "列強のプロパガンダが現れる。(1d6)を振り、その目が現在の《民の声》を上回っていたら、ランダムに列強1つを選びその属国になる",
  265. "新たな勢力が勃発する。王国シートの基地の土地欄の中から1つ、未知の土地を選ぶ。(1d6)を振り、その結果をその土地に記入する。1:敵対関係の国。2:険悪関係の国。3:凶暴な怪物の巣。4:人間嫌いのダンジョンマスターの庵。5:迷宮化の進んだ大迷宮。6:列強の飛び地",
  266. "何者かによる唐突な奇襲攻撃。未知の土地に面している領土からランダムに1つを選ぶ。[軍事レベル/敵対国数×2+険悪国数+9]の判定に失敗するとその領土は施設ごと失われる",
  267. "民の労働の結果が明らかに。[生活レベル/敵対国数×2+険悪国数+9]の判定に失敗したら《予算》が自国の領土のマップ数と同じだけ減る",
  268. "他国の使者がやってくる。基地の土地欄の中からランダムに自国以外の国を1つ選ぶ。その国の領土のマップ数を等しい《予算》を消費するとその国との関係が1段階よくなる。消費しないと1段階悪くなる",
  269. "民の声は離れ、この国を去る者たちがいた。《民》が(1d6)人減少する",
  270. "過ぎゆく時が王政を帰る。基地の土地欄の中から、経過したターン数と等しい数までランダムに他国を選ぶ。GMは、その国に面する未知の土地1つを選び、それをその国の新たな領土とする。(周囲に未知の土地がない場合は増やせない)",
  271. "街の機能に異変が!?[治安レベル/敵対国数×2+険悪国数+9]の判定に失敗したら、自国のタイプ:部屋の施設を1軒選び、破壊する",
  272. "王国同士の交流が行われた。[文化レベル/敵対国数×2+険悪国数+9]の判定に失敗すると、自国の逸材1人を選んで失い、ランダムに決めた国1つとの関係が1段階悪化する",
  273. "ただ、無為に時が過ぎていたわけではない。迷宮フェイズで過ごした1ターンにつき《予算》が1MG増える",
  274. "民の意識が大きく揺れる。(1d6)を振り、その目が現在の《民の声》を上回っていたら、好きな国力が1点減少する",
  275. ])
  276. end
  277. # 痛打表(2d6)
  278. 1 def mk_critical_attack_table
  279. 10 get_table_by_2d6([
  280. "攻撃の手応えが武器に刻まれる。その攻撃に使用した武具アイテムにレベルがあれば、そのレベルが1点上昇する",
  281. "電光石火の一撃。攻撃の処理が終了したあと、もう一度行動できる",
  282. "相手の姿形を変えるほどの一撃。攻撃目標に「呪い」のバッドステータスを与える",
  283. "乾坤一擲!攻撃の威力が2倍になる",
  284. "相手を吹き飛ばす一撃。攻撃目標を好きなエリアに移動させる",
  285. "会心の一撃!攻撃の威力+(1d6)",
  286. "相手の勢いを利用した一撃。攻撃の威力が攻撃目標のレベルと同じだけ上昇する",
  287. "あと1歩まで追いつめる。ダメージを与える代わりに、攻撃目標の残り《HP》を(1d6)点にすることができる",
  288. "敵の技を封じる。攻撃目標のスキルを1種選び、その戦闘の間、そのスキルを未修得の状態にする",
  289. "怒りの一撃!攻撃の威力+(2d6)",
  290. "急所をとらえ一撃で切り伏せる。攻撃目標の《HP》を0にする",
  291. ])
  292. end
  293. # 致命傷表(2d6)
  294. 1 def mk_fatal_wounds_table
  295. 10 get_table_by_2d6([
  296. "圧倒的一撃で急所を貫かれた。死亡する",
  297. "致命的な一撃が頭をかすめる。[探索/受けたダメージ+5]の判定に失敗すると死亡する",
  298. "出血多量で昏睡する。行動不能になる。この戦闘が終了するまでに《HP》を1以上にしないと死亡する",
  299. "頭を打ちつけ昏睡する。行動不能になる。このクォーターが終了するまでに《HP》を1以上にしないと死亡する",
  300. "重傷を負い昏睡する。行動不能になる。(1d6)クォーターが経過するまでに《HP》を1以上にしないと死亡する",
  301. "意識を失う。行動不能になる",
  302. "偶然アイテムに身を守られる。ランダムにアイテムを選び、そのアイテムを破壊してダメージを無効化する。破壊できるアイテムを1個も装備していない場合、行動不能になる",
  303. "《民》たちが身を挺して庇う。自分の《配下》を(2d6)人減少させ、ダメージを無効化する。《配下》が1人も居ない場合行動不能になる",
  304. "根性で跳ね返す。[探索/9-現在の《HP》]の判定に成功すると《HP》が1になる。失敗すると行動不能になる",
  305. "精神力だけで耐える。[武勇/9-現在の《HP》]の判定に成功すると《HP》が1になる。失敗すると行動不能になる",
  306. "幸運にもダメージを免れる。ダメージを無効化するが、代わりにランダムにバッドステータス1種を受ける",
  307. ])
  308. end
  309. # 道中表(2d6)
  310. 1 def mk_travel_table
  311. 10 get_table_by_2d6([
  312. "道中の時間が愛を育む。全員、好きなキャラ1体を選びそのキャラに対する《好意》+1",
  313. "何かの死体を見つけた。好きな素材1種類を(1d6)手に入れる",
  314. "辺りが闇に包まれる。宮廷の中からランダムにキャラを選ぶ。そのキャラが【星の欠片】を持っていたら、それが1個破壊される",
  315. "道に迷いそうになる。全員[才覚/9]の判定を行い、(1d6-成功したキャラ数)クォーター(最低0)、時間が経過する",
  316. "トラップに引っかかる。全員[探索/9]の判定にを行い、失敗したキャラは《HP》が(1d6)点減少する",
  317. "未知の土地の場合、何も起こらない。既知の土地の場合、その土地固有のイベントがある場合はそれが起こる",
  318. "モンスターの襲撃を受けた。全員[武勇/9]の判定を行い、失敗したキャラは《HP》が(1d6)点減少する",
  319. "恐ろしげな咆哮が響き渡る。全員[魅力/9]の判定を行い、失敗したキャラは《配下》が(1d6)人逃走し、自国へ帰る",
  320. "周辺の迷宮化が進む。宮廷全員は、既知の土地の中からランダムに選んだ土地へ移動する",
  321. "何かを拾う。コモンアイテムをランダムに1個選び、それを入手する",
  322. "1MG拾う",
  323. ])
  324. end
  325. # 交渉表(2d6)
  326. 1 def mk_negotiation_table
  327. 10 get_table_by_2d6([
  328. "中立的な態度は偽装だった。不意を打たれ、奇襲扱いで戦闘を行う",
  329. "交渉は決裂した。戦闘を行う",
  330. "交渉は決裂した。戦闘を行う",
  331. "生け贄を要求された。モンスターの中で最もレベルが高いもののレベルと同じだけ《配下》を減少させれば友好的になる。ただし、《民の声》-(1d6)。《配下》を減らさなければ戦闘を行う",
  332. "趣味を聞かれた。好きな単語表1つを選びD66を振る。宮廷の中に、その項目を好きなものに指定しているキャラがいれば友好的になる。居なければ戦闘を行う",
  333. "物欲しそうにこちらを見ている。「肉」の素材(1d6)個か、【お弁当】または【フルコース】1個を消費すれば友好的になる。しなければ戦闘を行う",
  334. "値踏みするようにこちらを見ている。維持費を(1d6)MG上昇させれば友好的になる。させなければ戦闘を行う",
  335. "「何かいいもの」を要求された。モンスターの中で最もレベルが高いもののレベル以上の価格のアイテムを消費すれば友好的になる。レアアイテムは価格を+10して扱う。しなければ戦闘を行う",
  336. "面白い話を要求された。プレイヤー達はモンスター達が興味を引きそうな話をすること。GMがそれを面白いと判断したら[魅力/9]の判定を行い、成功すれば。友好的になる。さもなければ戦闘を行う",
  337. "一騎打ちを申し込んできた。宮廷の中から代表を1名選び、モンスターの中で最もレベルの高いものと1対1で戦闘を行う(配置は互いに前列)。勝利すれば友好的になる。敗北すれば、再び交渉するか戦闘するかを決断する。この一騎打ちに外野がスキルやアイテムで干渉すると全員で戦闘になる",
  338. "運命の出会い。モンスター達の宮廷の代表に対する《好意》+1、友好的になる",
  339. ])
  340. end
  341. # 戦闘ファンブル表(2d6)
  342. 1 def mk_combat_fumble_table
  343. 10 get_table_by_2d6([
  344. "敵に援軍が現れる。敵軍の中で最もレベルの低いモンスターが(1d6)体増える。モンスター側がこの結果になった場合、好きなPCの《配下》+(1d6)",
  345. "敵の士気が大いに揺らぐ。自軍のキャラは全員1マス後退する",
  346. "勢い余って仲間を攻撃!自分の居るエリアからランダムに自軍のキャラを1体選び、そのキャラに使用している武器と同じ威力のダメージを与える",
  347. "つい仲間と口論になる。自軍の未行動キャラの中からランダムに1体選び、行動済みにする",
  348. "魔法の効果が消える。自軍のキャラが使用したスキルやアイテムの効果で、戦闘中持続するものが全て無効になる",
  349. "自分を傷つけてしまう。自分に(1d6)ダメージ",
  350. "攻撃の勢いを逆に利用される。自分の《HP》を現在値の半分にする",
  351. "アイテムを落とした。自分が装備しているアイテムからランダムに1個選び、破壊する。モンスター側の場合、自分に(1d6)ダメージ",
  352. "カーネルが活性化する。戦闘系とラップからランダムに1種類選び、それがその場に配置される",
  353. "空を切った攻撃に絶望する。自分と、自分に対して1点以上《好意》を持ったキャラ全員の《気力》-1。モンスター側の場合、自分に(1d6)ダメージ",
  354. "武器がすっぽ抜ける。攻撃に使用していたアイテムが破壊される。モンスター側の場合、自分に(1d6)ダメージ。その後、バトルフィールドにいるキャラの中からランダムに1体選び、そのキャラの《HP》を1点にする",
  355. ])
  356. end
  357. # 感情表(1d6)
  358. 1 def mk_emotion_table
  359. 10 get_table_by_1d3([
  360. "忠誠/怒り",
  361. "友情/不信",
  362. "愛情/侮蔑",
  363. ])
  364. end
  365. # 相場表(2d6)
  366. 1 def mk_market_price_table
  367. 11 get_table_by_2d6([
  368. "無し",
  369. "肉",
  370. "牙",
  371. "鉄",
  372. "魔素",
  373. "機械",
  374. "衣料",
  375. "木",
  376. "火薬",
  377. "情報",
  378. "革",
  379. ])
  380. end
  381. # お宝表1(1d6)
  382. 1 def mk_treasure1_table
  383. 10 get_table_by_1d6([
  384. "何も無し",
  385. "何も無し",
  386. "そのモンスターの素材欄の中から、好きな素材1個",
  387. "そのモンスターの素材欄の中から、好きな素材2個",
  388. "そのモンスターの素材欄の中から、好きな素材3個",
  389. "【お弁当】1個",
  390. ])
  391. end
  392. # お宝表2(1d6)
  393. 1 def mk_treasure2_table
  394. 10 get_table_by_1d6([
  395. "そのモンスターの素材欄の中から、好きな素材3個",
  396. "そのモンスターの素材欄の中から、好きな素材4個",
  397. "そのモンスターの素材欄の中から、好きな素材5個",
  398. "ランダムに回復アイテム1個",
  399. "ランダムに武具アイテム1個。レベルがあるアイテムなら1レベルのものが手に入る",
  400. "ランダムにレア一般アイテム1個",
  401. ])
  402. end
  403. # お宝表3(1d6)
  404. 1 def mk_treasure3_table
  405. 10 get_table_by_1d6([
  406. "そのモンスターの素材欄の中から、好きな素材5個",
  407. "そのモンスターの素材欄の中から、好きな素材7個",
  408. "そのモンスターの素材欄の中から、好きな素材10個",
  409. "好きなコモンアイテムのカテゴリ1種を選び、そのカテゴリからランダムにアイテム1個。レベルがあるアイテムなら1レベルのものが手に入る",
  410. "ランダムにレア一般アイテム1個。レベルがあるアイテムなら1レベルのものが手に入る",
  411. "ランダムにレア武具アイテム1個",
  412. ])
  413. end
  414. # お宝表4(1d6)
  415. 1 def mk_treasure4_table
  416. 10 get_table_by_1d6([
  417. "そのモンスターの素材欄の中から、好きな素材5個",
  418. "そのモンスターの素材欄の中から、好きな素材10個",
  419. "好きなコモンアイテムのカテゴリ1種を選び、そのカテゴリからランダムにアイテム1個。レベルがあるアイテムなら2レベルのものが手に入る",
  420. "好きなコモンアイテムのカテゴリ1種を選び、そのカテゴリからランダムにアイテム1個。レベルがあるアイテムなら3レベルのものが手に入る",
  421. "ランダムにレア一般アイテム1個。レベルのあるアイテムなら2レベルのものが手に入る",
  422. "ランダムにレア武具アイテム1個。レベルのあるアイテムなら1レベルのものが手に入る",
  423. ])
  424. end
  425. # お宝表5(1d6)
  426. 1 def mk_treasure5_table
  427. 10 get_table_by_1d6([
  428. "そのモンスターの素材欄の中から、好きな素材10個",
  429. "そのモンスターの素材欄の中から、好きな素材15個",
  430. "好きなコモンアイテムのカテゴリ1種を選び、そのカテゴリからランダムにアイテム1個。レベルがあるアイテムなら4レベルのものが手に入る",
  431. "ランダムにレア一般アイテム1個。レベルのあるアイテムなら3レベルのものが手に入る",
  432. "ランダムにレア武具アイテム1個。レベルのあるアイテムなら2レベルのものが手に入る",
  433. "好きなレアアイテム1個",
  434. ])
  435. end
  436. # 1レベルランダムエンカウント表(1D6)
  437. 1 def mk_random_encount1_table(num)
  438. table = [
  439. 10 [1, "『守って守って突撃ゴー!』 前衛:ごんぎつね×宮廷の人数、後衛:ノコギリ猪×1"],
  440. [2, "『じわじわ削る、カボチャの舞』 前衛:焔虫×宮廷の人数、本陣:カボチャ頭×宮廷の人数の半分"],
  441. [3, "『ものすごくジャマな人たち。』 前衛:小人さん×宮廷の人数、取り替え子×宮廷の人数の半分"],
  442. [4, "『何かやってくれるかも……』 前衛:兵隊エルフ×宮廷の人数"],
  443. [5, "『【かばう】で延命しつつ【鉄の勇気】』 前衛:キンギョ×宮廷の人数、本陣:イカロス×宮廷の人数の半分"],
  444. [6, "『英雄で指示してシュシュシュシュ~~~~ト!!』 前衛:小鬼×宮廷の人数、後衛:小鬼×宮廷の人数、本陣:小鬼大砲×1、小鬼英雄×1"],
  445. ]
  446. 10 return get_table_by_number(num, table)
  447. end
  448. # 2レベルランダムエンカウント表(1D6)
  449. 1 def mk_random_encount2_table(num)
  450. table = [
  451. 10 [1, "『作戦判定に負けてもOK、そして強い』 前衛:ガーゴイル×宮廷の人数"],
  452. [2, "『吸い殺せ! ドレインしまくれ!』 後衛:塚人×宮廷の人数の半分"],
  453. [3, "『ゴールデンコンビ結成。指揮と【鉄腕】+【範囲攻撃】で大暴れ』 前衛:牛頭×宮廷の人数の半分、後衛:山羊頭×宮廷の人数の半分"],
  454. [4, "『クピドは野放しにできないが、ハルキュオネは殺せない。このジレンマが……』 前衛:ハルキュオネ×宮廷の人数、後衛:ハルキュオネ×宮廷の人数、本陣:クピド×宮廷の人数の半分"],
  455. [5, "『眠りコンボ』 前衛:グレムリン×宮廷の人数、本陣:眠りの精×1"],
  456. [6, "『回避を減らしてみみずの範囲攻撃』 前衛:みみず×宮廷の人数、本陣:大喰らい×宮廷の人数の半分"],
  457. ]
  458. 10 return get_table_by_number(num, table)
  459. end
  460. # 3レベルランダムエンカウント表(1D6)
  461. 1 def mk_random_encount3_table(num)
  462. table = [
  463. 10 [1, "『魅了→木霊ハメ』 後衛:淫魔×1、本陣:レーシィ×宮廷の人数"],
  464. [2, "『素早く【多勢に無勢】をしかけ……たい』 前衛:階賊×宮廷の人数、本陣:抜け忍×1"],
  465. [3, "『倒しても嬉しくない人柱をどうぞ』 前衛:人柱×宮廷の人数、本陣:恋のぼり×宮廷の人数の半分"],
  466. [4, "『位置を調整して【抱擁】してみよう』 後衛:霧妾×宮廷の人数、本陣:お化けシーツ×宮廷の人数"],
  467. [5, "『クリティカルヒットしたい(希望)』 後衛:ヴォーパルバニー×宮廷の人数、本陣:二面人×1"],
  468. [6, "『なんとか特攻したい(願望)』 前衛:穴人×宮廷の人数、ゴーレム×1"],
  469. ]
  470. 10 return get_table_by_number(num, table)
  471. end
  472. # 4レベルランダムエンカウント表(1D6)
  473. 1 def mk_random_encount4_table(num)
  474. table = [
  475. 10 [1, "『増やして治す。ド外道タッグが嵐を呼ぶぜ』 前衛:闇双子×1、本陣:坊主子牛×宮廷の人数の半分"],
  476. [2, "『カリスマ的存在+平和の使者→エセNGOみたいな?』 前衛:ワリアヒラ×宮廷の人数、後衛:妖精騎士×1"],
  477. [3, "『【星戦】→攻撃、【星界】→【ベアハッグ】』 前衛:洞窟熊×宮廷の人数、本陣:星人×宮廷の人数の半分"],
  478. [4, "『さりげなく先攻を取りつつ《民》をバイドバイパー作戦』 前衛:大目玉×宮廷の人数、本陣:笛吹き男×宮廷の人数の半分"],
  479. [5, "『アンデッドチーム、がんばれ!』 前衛:墓暴き×宮廷の人数、本陣:吸血鬼×1"],
  480. [6, "『まよセレ、このゲームの代名詞(?)。こいつは欠かせない!』 後衛:マヨネーズキング・ピュアセレクト×宮廷の人数、本陣:メイクイーン×1"],
  481. ]
  482. 10 return get_table_by_number(num, table)
  483. end
  484. # 5レベルランダムエンカウント表(1D6)
  485. 1 def mk_random_encount5_table(num)
  486. table = [
  487. 10 [1, "『「死ぬが良い」最終鬼畜兵器岸降臨』 前衛:暗黒騎士×1"],
  488. [2, "『割と痛い。さりげなく魔王が分裂する』 前衛:カミツキ魔王×宮廷の人数の半分、本陣:雷鳥×1"],
  489. [3, "『ハマると死ぬ。5人パーティだと3体出てザマーミロ』 前衛:ヴァララカール×宮廷の人数の半分"],
  490. [4, "『不意打ちされたらデンジャー。ひそかにワイヴァーンで先手を取る』 前衛:睨み毒蛇×宮廷の人数の半分、後衛:ワイヴァーン×1"],
  491. [5, "『ゾンビスペシャル……で、がんばりたい』 前衛:死にぞこない×宮廷の人数の半分、後衛:死にぞこない×宮廷の人数の半分、本陣:屍術師×1"],
  492. [6, "『とにかく殴れ! 単純明快パワーチーム』 前衛:鮫人×宮廷の人数、夜這い海星×1"],
  493. ]
  494. 10 return get_table_by_number(num, table)
  495. end
  496. # 6レベルランダムエンカウント表(1D6)
  497. 1 def mk_random_encount6_table(num)
  498. table = [
  499. 10 [1, "『死んでください。【外皮】か【甲冑】がないと相当ヤバい』 本陣:死告天使×宮廷の人数"],
  500. [2, "『ド迫力。ブレス連発。3体出ちゃったらカーニバル』 本陣:ドラゴン×宮廷の人数の半分"],
  501. [3, "『死霊のボス。スキル次第でヤバい。GMの悪意が閃くときだ』 本陣:骨龍×1、推奨スキル【不滅の炎】、【困惑】、【ヤバチョンガー】など"],
  502. [4, "『《好意》を消して【魅了】に持ち込む』 後衛:愛染明王×宮廷の人数"],
  503. [5, "『真の狙いは【蜘蛛の群れ】』 前衛:アラクネ×宮廷の人数、本陣:蜘蛛の王×1"],
  504. [6, "『お約束。まあこいつは出るだろうみたいな』 前衛:魔蟹×1、帳魚×1"],
  505. ]
  506. 10 return get_table_by_number(num, table)
  507. end
  508. 1 def getAftersearchBreakTable()
  509. 2 get_table_by_2d6([
  510. "「おつとめ、ご苦労様です」同行する民たちが感謝の言葉をかける。《民の声》が1点回復する。",
  511. "「おい、サボるな」と仲間から怒られた。いやいや、こっちは今までマジメにやってましたよ。宮廷の中から好きなキャラクター1人を選ぶ。自分のそのキャラクターに対する《敵意》が1点上昇する。",
  512. "大漁大漁! 色々な素材が見つかる。肉、牙、革、木、鉄の素材(キャラクターシートの上の段の素材)を1個ずつ獲得する。",
  513. "そこは、もう、使い魔が探索してくれていたようだ。サンキュー相棒! この捜索の判定に【使い魔】を利用していれば、行動済みにならず、さらにもう1回行動を行うことができる。",
  514. "危険なトラップを見つけたが、なんとか無力化できた。任務完了。自分の《気力》が1点回復する。",
  515. "何も見つからなかったか、と思っていたら「いつも、ありがとう」と宮廷の仲間から声をかけられた。まぁ、何もない方がいいか。宮廷の中から好きなキャラクター1人を選ぶ。自分のそのキャラクターに対する《好意》が1点上昇する。",
  516. "「さすが! 素晴らしいお手並みだ」鮮やかな捜索に、仲間の見る目が変わる。宮廷の中から好きなキャラクター1人を選ぶ。そのキャラクターの自分に対する《好意》が1点上昇する。",
  517. "よしよし、これはいいものが見つかった。好きな素材を1d6個獲得する。この捜索の判定に【使い魔】を使用していれば、獲得数が1d6個上昇する。",
  518. "大漁大漁! 色々な素材が見つかる。衣料、魔素、機械、火薬、情報の素材(キャラクターシートの上の段の素材)を1個ずつ獲得する。",
  519. "うわ! 罠だ。余計なものまで見つけてしまった。宮廷全員は1d6点のダメージを受ける。",
  520. "「へぇ、こんなヤツだったのか」仲間の意外な一面を見つける。宮廷の中から好きなキャラクター1人を選ぶ。自分のそのキャラクターに対する《好意》か《敵意》を1点上昇させ、その属性を好きなものに変更できる。",
  521. ])
  522. end
  523. 1 def getWholeBreakTable()
  524. 2 get_table_by_2d6([
  525. "部屋の中から使えそうな装備をみつくろう。宮廷全員は、それぞれ好きなコモンアイテムのカテゴリを選び、そのランダムにコモンアイテムを1つ獲得する。そのアイテムにレベルがあれば、それは1レベルのものとなる。",
  526. "みんなで今後の作戦を練る。宮廷全員は、そのターンの間、あらゆる判定の達成値が1上昇する。",
  527. "手分けして物資の調達を行う。各キャラクターは、好きな素材を1d6個獲得できる。このとき、素材が揃っていれば、各キャラクターにつき1個までアイテムを作成することができる。",
  528. "体を休めながら他愛もない世間話に花が咲く。宮廷全員は、それぞれ宮廷の中から好きなキャラクター1人を選び、そのキャラクターに対する《好意》が1点上昇する。",
  529. "宮廷メンバーで交代で見張りを行い、疲労した配下たちを休ませる。《民の声》が宮廷の人数と同じ値だけ回復する。",
  530. "一行はしっかりと休息を取り、鋭気を養う。宮廷全員の《気力》が1点回復する。",
  531. "配下たちと一緒に体を休める。《民の声》が1d6点回復する。",
  532. "配下たちに見張りを任せ、体を休める。宮廷全員の《HP》がすべて回復する。",
  533. "緊急ミーティング! 国家運営に関してみんなで知恵を出し合う。《予算》を[宮廷の人数*1]MG獲得する。",
  534. "負傷した配下たちの治療を行う。宮廷全員の《配下》が1d6人回復する。",
  535. "宮廷の前に光り輝くアイテムが降臨する。レア武具アイテムかレア一般アイテムのどちらかを選ぶ。ランダムにそのアイテムを1つ選び、それを獲得する。",
  536. ])
  537. end
  538. 1 def getLoversBreakTable()
  539. table = [
  540. 2 [11, "「あーもう、最悪!」仲良く休憩するつもりが、ひどい喧嘩になってしまう。この表の使用者のお互いに対する《好意》が0になり、その値の分だけお互いに対する《敵意》が上昇する。"],
  541. [12, "「何もかもがお前が悪かったのかッ!!」大きな誤解が生まれる。受け身キャラの攻め気キャラ以外に対する《敵意》がすべて0になり、その値の分だけ攻め気キャラに対する《敵意》が上昇する。"],
  542. [13, "「でさぁ、あの人のことなんだけど……」せっかく2人きりなのに、他人の話で盛り上がる。この表の使用者は、宮廷の中からこの表の使用者以外のキャラクター1人を選び、そのキャラクターに対する《好意》が1点上昇する。"],
  543. [14, "「へぇ、そんなのあるんだ」互いの好きなものについて語り合う。受け身キャラは、攻め気キャラの「好きなもの」1つを選ぶ。受け身キャラは、自分の「好きなもの」1つをそれに変更し、攻め気キャラへの《好意》が1点上昇する。"],
  544. [15, "「なぁ、オレのことどう思う?」思い切った質問! 受け身キャラは、攻め気キャラに対する《好意》か《敵意》を1点上昇させ、その属性を好きなものに変更できる。"],
  545. [16, "「だいじょうぶ? 無茶するんだから」少し前の失敗について色々と言われてしまう。ありがたいんだけど、少しムカつく。受け身キャラは、攻め気キャラに対する《好意》と《敵意》が1点ずつ上昇する。"],
  546. [22, "「え、もうこんな時間!?」一休みするつもりが、気がつくとかなり時間がたっている。宮廷の未行動キャラクターが全員行動済みになったら、通常の時間の経過に加え、さらに1クォーターが経過する。この表の使用者のお互いに対する《好意》が1点上昇する。また、宮廷のこの表の使用者2人に対する《敵意》が1点上昇する。"],
  547. [23, "「ねぇねぇ、これわかる?」何気ない質問だが、これは難しい。変な答えは出来ないぞ。攻め気キャラは、〔才覚〕で難易度9の判定を行う。成功すると、この表の使用者のお互いに対する《好意》が1点上昇する。失敗すると、なんとか危機を切り抜けることができるが、受け身キャラの攻め気キャラに対する《敵意》が1点上昇する。"],
  548. [24, "「おいおい、まずは落ち着け」配下同士が喧嘩を始めた。うまく仲裁しないと……。攻め気キャラは、〔魅力〕で難易度9の判定を行う。成功すると、この表の使用者のお互いに対する《好意》が1点上昇する。失敗すると、なんとか危機を切り抜けることができるが、受け身キャラの攻め気キャラに帯する《敵意》が1点上昇する。"],
  549. [25, "「オレが解除するからちょっと待ってろ」2人で休憩するつもりが、一緒にトラップにひっかかってしまった。互いの体が密着してしまう。攻め気キャラは、〔探索〕で難易度9の判定を行う。成功すると、この表の使用者のお互いに対する《好意》が1点上昇する。失敗すると、なんとか危機を切り抜けることができるが、受け身キャラの攻め気キャラに対する《敵意》が1点上昇する。"],
  550. [26, "「お前は後ろに下がってろ!」休憩中に怪物に襲われる。攻め気キャラは、〔武勇〕で難易度9の判定を行う。成功すると、この表の使用者のお互いに対する《好意》が1点上昇する。失敗すると、なんとか危機を切り抜けることができるが、受け身キャラの攻め気キャラに対する《敵意》が1点上昇する。"],
  551. [33, "「なぁ、さっきは悪かったな」誤解が解ける。この表の使用者のお互いに対する《敵意》が0になり、その値のぶんだけお互いに対する《好意》が上昇する。"],
  552. [34, "「これを言ったのはあなただけです。誰にも言わないでくださいね」受け身キャラが隠している夢や秘密を攻め気キャラが知ってしまう。受け身キャラの攻め気キャラに対する《好意》が1点上昇する。攻め気キャラの受け身キャラに対する《好意》の属性が「忠誠」に変わる。"],
  553. [35, "「これからも、よろしく頼むぜ。相棒」攻め気キャラが快活に微笑む。受け身キャラの攻め気キャラに対する《好意》が1点上昇する。攻め気キャラの受け身キャラに対する《好意》の属性が「友情」に変わる。"],
  554. [36, "「わ、わたしは、あなたのことが……」受け身キャラの思わぬ告白! 受け身キャラの攻め気キャラに対する《好意》が1点上昇する。攻め気キャラの受け身キャラに対する《好意》の属性が「愛情」に変わる。"],
  555. [44, "「大丈夫? 痛くないか?」互いに傷を治療しあう。この表の使用者は、お互いの自分に対する《好意》の分だけ、自分の《HP》を回復することができる。どちらかが《HP》が1点以上回復したら、この表の使用者のお互いに対する《好意》が1点上昇する。"],
  556. [45, "「この冒険が終わったら、伝えたいことが……あるんだ」攻め気キャラの真剣な言葉。え、それって……? 受け身キャラの攻め気キャラに対する《好意》が1点上昇する。エピローグに攻め気キャラが生きていれば、この表の使用者のお互いに対する《好意》が2点上昇する。ただし、以後このゲームの間、攻め気キャラが「致命傷表」を使用することになった場合、余分に1個サイコロを振り、その中からもっとも低い目2つを選んで、その結果を適用する。"],
  557. [46, "「蝕ッ!? ……って、どこ触ってるんですかッ!?」あたりが不意に暗くなり、思わず変なところを触ってしまう。攻め気キャラの受け身キャラに対する《好意》が2点上昇し、受け身キャラの攻め気キャラに対する《敵意》が2点上昇する。この表の使用者が持っている【星の欠片】1個を破壊すれば、このイベントをなかったことにできる。"],
  558. [55, "「これ、はんぶんこしない?」2人仲良く、アイテムを分け合う。この表の使用者が、使用するとなくなる回復アイテムを持っていれば、それを1個使用出来る。ただし、その効果の大賞は、この表を使用した2人に変更される。この表の使用者のお互いに対する《好意》が1点上昇する。"],
  559. [56, "「え? え? えぇぇぇぇッ!?」ふとした拍子に唇がふれあう。受け身キャラの攻め気キャラ以外に対する《好意》がすべて0になり、その値のぶんだけ攻め気キャラに対する《好意》が上昇する。"],
  560. [66, "「…………」気がつくとお互い、目をそらせなくなってしまう。そのまま顔を寄せ合い……。この表の使用者のお互いに対する《好意》が2点上昇し、その属性を「愛情」にする。"],
  561. ]
  562. 2 value = @randomizer.roll_d66(D66SortType::ASC)
  563. 2 return get_table_by_number(value, table), value
  564. end
  565. end
  566. end
  567. end

lib/bcdice/game_system/meikyu_kingdom/word_table.rb

100.0% lines covered

100.0% branches covered

15 relevant lines. 15 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MeikyuKingdom
  5. # 単語表1(D66)
  6. 1 def mk_word_1_table(num)
  7. table = [
  8. 1 [11, "魔法"],
  9. [12, "おめかし"],
  10. [13, "狭いところ"],
  11. [14, "夜更かし"],
  12. [15, "節約"],
  13. [16, "会議"],
  14. [22, "ヒゲ"],
  15. [23, "孤独"],
  16. [24, "自慢話"],
  17. [25, "自分探し"],
  18. [26, "異性"],
  19. [33, "ヒラヒラした服"],
  20. [34, "平穏な生活"],
  21. [35, "自分語り"],
  22. [36, "風呂"],
  23. [44, "古いもの"],
  24. [45, "頭が悪い人"],
  25. [46, "暗闇"],
  26. [55, "許嫁"],
  27. [56, "民"],
  28. [66, "バカ"],
  29. ]
  30. 1 return get_table_by_number(num, table)
  31. end
  32. # 単語表2(D66)
  33. 1 def mk_word_2_table(num)
  34. table = [
  35. 1 [11, "科学"],
  36. [12, "読書"],
  37. [13, "広いところ"],
  38. [14, "早起き"],
  39. [15, "ムダ"],
  40. [16, "仕事"],
  41. [22, "ハゲ"],
  42. [23, "みんなで集まること"],
  43. [24, "ナンパ"],
  44. [25, "昔話"],
  45. [26, "同性"],
  46. [33, "武器の手入れ"],
  47. [34, "戦争"],
  48. [35, "人の噂"],
  49. [36, "散髪"],
  50. [44, "新しいもの"],
  51. [45, "頭がよい人"],
  52. [46, "光"],
  53. [55, "親"],
  54. [56, "王様"],
  55. [66, "ホラ話"],
  56. ]
  57. 1 return get_table_by_number(num, table)
  58. end
  59. # 単語表3(D66)
  60. 1 def mk_word_3_table(num)
  61. table = [
  62. 1 [11, "子供"],
  63. [12, "弱い人"],
  64. [13, "処刑"],
  65. [14, "叙事詩"],
  66. [15, "煙草"],
  67. [16, "病院"],
  68. [22, "目立つこと"],
  69. [23, "酒盛り"],
  70. [24, "料理"],
  71. [25, "武芸"],
  72. [26, "田舎"],
  73. [33, "自分の国"],
  74. [34, "伝統"],
  75. [35, "セレモニー"],
  76. [36, "告げ口"],
  77. [44, "自分の声"],
  78. [45, "マヨネーズ"],
  79. [46, "おせっかい"],
  80. [55, "外国人"],
  81. [56, "迷宮"],
  82. [66, "ねこみみ"],
  83. ]
  84. 1 return get_table_by_number(num, table)
  85. end
  86. # 単語表4(D66)
  87. 1 def mk_word_4_table(num)
  88. table = [
  89. 1 [11, "年寄り"],
  90. [12, "強い人"],
  91. [13, "空想"],
  92. [14, "冗談"],
  93. [15, "クスリ"],
  94. [16, "怪物"],
  95. [22, "一騎打ち"],
  96. [23, "賭け事"],
  97. [24, "歌"],
  98. [25, "勉強"],
  99. [26, "都会"],
  100. [33, "冒険"],
  101. [34, "ダイナマイト大帝"],
  102. [35, "悪事"],
  103. [36, "言い訳"],
  104. [44, "隣のキャラのジョブ"],
  105. [45, "小鬼"],
  106. [46, "謝ること"],
  107. [55, "異種族"],
  108. [56, "星"],
  109. [66, "虫"],
  110. ]
  111. 1 return get_table_by_number(num, table)
  112. end
  113. end
  114. end
  115. end

lib/bcdice/game_system/meikyu_kingdom_basic/item_table.rb

100.0% lines covered

100.0% branches covered

53 relevant lines. 53 lines covered and 0 lines missed.
5 total branches, 5 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MeikyuKingdomBasic
  5. 1 WEAPON_ITEM_TABLE = DiceTable::D66Table.new(
  6. "武具アイテム表",
  7. D66SortType::ASC,
  8. {
  9. 11 => "だんびら",
  10. 12 => "網(だんびら)",
  11. 13 => "短剣",
  12. 14 => "戦斧",
  13. 15 => "盾",
  14. 16 => "ホウキ",
  15. 22 => "棘(だんびら)",
  16. 23 => "鑓",
  17. 24 => "石弓",
  18. 25 => "甲冑",
  19. 26 => "戦鎚",
  20. 33 => "鎖(だんびら)",
  21. 34 => "爆弾",
  22. 35 => "鉄砲",
  23. 36 => "大剣",
  24. 44 => "大弓(だんびら)",
  25. 45 => "徹甲弾",
  26. 46 => "拳銃",
  27. 55 => "手裏剣(だんびら)",
  28. 56 => "大砲",
  29. 66 => "籠手(だんびら)",
  30. }
  31. )
  32. 1 LIFE_ITEM_TABLE = DiceTable::D66Table.new(
  33. "生活アイテム表",
  34. D66SortType::ASC,
  35. {
  36. 11 => "鍋",
  37. 12 => "家畜(鍋)",
  38. 13 => "バックパック",
  39. 14 => "クラッカー",
  40. 15 => "がまぐち",
  41. 16 => "マント",
  42. 22 => "裁縫道具(鍋)",
  43. 23 => "カード",
  44. 24 => "エプロン",
  45. 25 => "住民台帳",
  46. 26 => "携帯電話",
  47. 33 => "外套(鍋)",
  48. 34 => "肖像画",
  49. 35 => "衣装",
  50. 36 => "山吹色のお菓子",
  51. 44 => "鏡(鍋)",
  52. 45 => "眼鏡",
  53. 46 => "クレジットカード",
  54. 55 => "召喚鍵(鍋)",
  55. 56 => "魔道書",
  56. 66 => "宝石(鍋)",
  57. }
  58. )
  59. 1 REST_ITEM_TABLE = DiceTable::D66Table.new(
  60. "回復アイテム表",
  61. D66SortType::ASC,
  62. {
  63. 11 => "チョコレート(お弁当)",
  64. 12 => "砂糖菓子(お弁当)",
  65. 13 => "特効薬",
  66. 14 => "保存食",
  67. 15 => "担架",
  68. 16 => "お弁当(チョコレート)",
  69. 22 => "バナナ(お弁当)",
  70. 23 => "お酒",
  71. 24 => "珈琲",
  72. 25 => "フルコース",
  73. 26 => "ポーション",
  74. 33 => "魔素水(お弁当)",
  75. 34 => "救急箱",
  76. 35 => "強壮剤",
  77. 36 => "迷宮保険",
  78. 44 => "魔薬(お弁当)",
  79. 45 => "科学調味料",
  80. 46 => "惚れ薬",
  81. 55 => "軟膏(お弁当)",
  82. 56 => "復活薬",
  83. 66 => "万能薬(お弁当)",
  84. }
  85. )
  86. 1 SEARCH_ITEM_TABLE = DiceTable::D66Table.new(
  87. "探索アイテム表",
  88. D66SortType::ASC,
  89. {
  90. 11 => "拷問具(星の欠片)",
  91. 12 => "ロープ(星の欠片)",
  92. 13 => "旗",
  93. 14 => "お守り",
  94. 15 => "星の欠片(拷問具)",
  95. 16 => "パワーリスト",
  96. 22 => "松明(星の欠片)",
  97. 23 => "テント",
  98. 24 => "楽器",
  99. 25 => "工具",
  100. 26 => "使い魔",
  101. 33 => "迷宮迷彩(星の欠片)",
  102. 34 => "乗騎",
  103. 35 => "罠百科",
  104. 36 => "迷宮防護服",
  105. 44 => "聴診器(星の欠片)",
  106. 45 => "地図",
  107. 46 => "時計",
  108. 55 => "飛行騎(星の欠片)",
  109. 56 => "カボチャの馬車",
  110. 66 => "もぐら棒(星の欠片)",
  111. }
  112. )
  113. 1 COMMON_ITEM_RANDOM_TABLE = DiceTable::ChainTable.new(
  114. "コモンアイテムランダム決定表",
  115. "1D4",
  116. [
  117. WEAPON_ITEM_TABLE,
  118. LIFE_ITEM_TABLE,
  119. REST_ITEM_TABLE,
  120. SEARCH_ITEM_TABLE,
  121. ]
  122. )
  123. 1 NORMAL_RARE_ITEM_TABLE = DiceTable::D66GridTable.new(
  124. "基本レア一般アイテム表",
  125. [
  126. ["愚者の冠", "香水", "煙玉", "悪名", "藁人形", "王妃の鏡"],
  127. ["星籠", "転ばぬ先の杖", "悟りの書", "鉛の兵隊", "黄金の林檎", "百年茸"],
  128. ["愚者の冠", "香水", "煙玉", "悪名", "藁人形", "王妃の鏡"],
  129. ["星籠", "転ばぬ先の杖", "悟りの書", "鉛の兵隊", "黄金の林檎", "百年茸"],
  130. ["操りロープ", "盗賊の七つ道具", "露眼鏡", "災厄王の遺物", "魔法の鞍", "琵琶"],
  131. ["兎の足", "視肉", "衛星帯", "魔法の絨毯", "軍配", "聖杯"],
  132. ]
  133. )
  134. 1 ADVANCED_RARE_ITEM_TABLE = DiceTable::D66GridTable.new(
  135. "上級レア一般アイテム表",
  136. [
  137. ["砂時計週報", "兵糧丸", "遊星葉書", "百科辞典", "夢枕", "蓄音機"],
  138. ["砂時計週報", "兵糧丸", "遊星葉書", "百科辞典", "夢枕", "蓄音機"],
  139. ["水晶球", "狭間の棺桶", "不思議なたまご", "魔法瓶", "不死鳥の羽飾り", "紅葫蘆"],
  140. ["水晶球", "狭間の棺桶", "不思議なたまご", "魔法瓶", "不死鳥の羽飾り", "紅葫蘆"],
  141. ["打ち出の小槌", "消火器", "滅びの予言書", "召魔鏡", "鉄仮面", "愛"],
  142. ["打ち出の小槌", "消火器", "滅びの予言書", "召魔鏡", "鉄仮面", "愛"],
  143. ]
  144. )
  145. 1 RARE_ITEM_RANDOM_TABLE = DiceTable::ChainTable.new(
  146. "レア一般アイテムランダム決定表",
  147. "1D6",
  148. [
  149. NORMAL_RARE_ITEM_TABLE,
  150. NORMAL_RARE_ITEM_TABLE,
  151. NORMAL_RARE_ITEM_TABLE,
  152. ADVANCED_RARE_ITEM_TABLE,
  153. ADVANCED_RARE_ITEM_TABLE,
  154. ADVANCED_RARE_ITEM_TABLE,
  155. ]
  156. )
  157. 1 NORMAL_RARE_WEAPON_ITEM_TABLE = DiceTable::D66GridTable.new(
  158. "基本レア武具アイテム表",
  159. [
  160. ["蛍矢", "小麦粉", "喇叭銃", "まわし", "しゃべる剣", "大盾"],
  161. ["王笏", "ぬいぐるみ", "魔杖", "獣の毛皮", "バカには見えない鎧", "ビキニアーマー"],
  162. ["蛍矢", "小麦粉", "喇叭銃", "まわし", "しゃべる剣", "大盾"],
  163. ["王笏", "ぬいぐるみ", "魔杖", "獣の毛皮", "バカには見えない鎧", "ビキニアーマー"],
  164. ["チェインソード", "輝く者", "貪る者", "滅ぼす者", "機械の体", "刈り取る者"],
  165. ["断ち切る者", "竜の鱗鎧", "射貫く者", "貫く者", "剥ぎ取る者", "王剣"],
  166. ]
  167. )
  168. 1 ADVANCED_RARE_WEAPON_ITEM_TABLE = DiceTable::D66GridTable.new(
  169. "上級レア武具アイテム表",
  170. [
  171. ["虚弾", "小鬼の襟巻", "眼弾", "釣竿", "虹柱", "服従の鞭"],
  172. ["虚弾", "小鬼の襟巻", "眼弾", "釣竿", "虹柱", "服従の鞭"],
  173. ["星の杖", "聖印", "迷い傘", "邪眼", "徒手空拳", "隠れ兜"],
  174. ["星の杖", "聖印", "迷い傘", "邪眼", "徒手空拳", "隠れ兜"],
  175. ["太刀鋏", "破城槌", "黄金の鶴嘴", "ムラサマ", "君主の衣", "蒸気甲冑"],
  176. ["太刀鋏", "破城槌", "黄金の鶴嘴", "ムラサマ", "君主の衣", "蒸気甲冑"],
  177. ]
  178. )
  179. 1 RARE_WEAPON_ITEM_RANDOM_TABLE = DiceTable::ChainTable.new(
  180. "レア武具アイテムランダム決定表",
  181. "1D6",
  182. [
  183. NORMAL_RARE_WEAPON_ITEM_TABLE,
  184. NORMAL_RARE_WEAPON_ITEM_TABLE,
  185. NORMAL_RARE_WEAPON_ITEM_TABLE,
  186. ADVANCED_RARE_WEAPON_ITEM_TABLE,
  187. ADVANCED_RARE_WEAPON_ITEM_TABLE,
  188. ADVANCED_RARE_WEAPON_ITEM_TABLE,
  189. ]
  190. )
  191. # デヴァイス・ファクトリー
  192. 1 def roll_device_factory_table(num)
  193. 4 item = ITEM_RANDOM_TABLE.roll(@randomizer).last_body
  194. 4 intro = "デヴァイス・ファクトリー表 (特性#{num}個) > ベースアイテム:#{item}(もしくは任意のアイテム)"
  195. 4 num = [0, num].max
  196. 9 feature_list = Array.new(num) { ITEM_FEATURES_TABLE.roll(randomizer) }
  197. 4 return [intro, *feature_list].join("\n")
  198. end
  199. # アイテムカテゴリ決定表 (1D6)
  200. 1 ITEM_RANDOM_TABLE = DiceTable::ChainTable.new(
  201. "アイテムカテゴリ決定表",
  202. "1D6",
  203. [
  204. WEAPON_ITEM_TABLE,
  205. LIFE_ITEM_TABLE,
  206. REST_ITEM_TABLE,
  207. SEARCH_ITEM_TABLE,
  208. RARE_ITEM_RANDOM_TABLE,
  209. RARE_WEAPON_ITEM_RANDOM_TABLE,
  210. ]
  211. )
  212. 1 class ItemFeature
  213. 1 def initialize(name, type, items)
  214. 6 @name = name
  215. 6 @times, @sides = type.split("D", 2).map(&:to_i)
  216. 6 @items = items
  217. end
  218. 1 def choice(randomizer)
  219. 11 dice = randomizer.roll_sum(@times, @sides)
  220. 11 index = dice - @times
  221. 11 chosen = @items[index]
  222. 11 then: 3 else: 8 chosen = chosen.choice(randomizer) if chosen.respond_to?(:choice)
  223. 11 return "[#{dice}]#{chosen}"
  224. end
  225. end
  226. 1 ITEM_POWER_TABLE = ItemFeature.new(
  227. "神力決定表",
  228. "1D6",
  229. [
  230. "才覚",
  231. "魅力",
  232. "探索",
  233. "武勇",
  234. "《器》",
  235. "《回避値》",
  236. ]
  237. )
  238. 1 ITEM_JYUMON_TABLE = ItemFeature.new(
  239. "呪紋決定表",
  240. "2D6",
  241. [
  242. "ランダムに選んだモンスターカテゴリ1種のうち、【人類の敵】未習得かつ(2D6)レベル以下のモンスタースキル",
  243. "便利スキルから好きなスキル1種",
  244. "芸能スキルから好きなスキル1種",
  245. "迷宮スキルから好きなスキル1種",
  246. "星術スキルから好きなスキル1種",
  247. "一般スキルから好きなスキル1種",
  248. "召喚スキルから好きなスキル1種",
  249. "科学スキルから好きなスキル1種",
  250. "交渉スキルから好きなスキル1種",
  251. "神官のクラススキルから好きなスキル1種",
  252. "生まれ表を使用してランダムに決めたジョブのジョブスキル",
  253. ]
  254. )
  255. 1 ITEM_JYUKA_TABLE = ItemFeature.new(
  256. "呪禍表",
  257. "1D6",
  258. [
  259. "このアイテムを装備している限り「呪い3」の変調を受ける",
  260. "このアイテムを装備している限り「肥満3」の変調を受ける",
  261. "このアイテムを装備している限り「憤怒」の変調を受ける",
  262. "このアイテムを装備している限り「毒2」の変調を受ける",
  263. "このアイテムを装備している限り、条件を満たしても誰とも人間関係を結べない",
  264. "このアイテムを装備している限り「散漫1」の変調を受ける",
  265. ]
  266. )
  267. 1 GENDER_TABLE = ItemFeature.new(
  268. "性別決定表",
  269. "1D6",
  270. [
  271. "性別が男であること",
  272. "性別が女であること",
  273. "性別が男であること",
  274. "性別が女であること",
  275. "性別が男であること",
  276. "性別が女であること",
  277. ]
  278. )
  279. 1 ITEM_APTITUDE_TABLE = ItemFeature.new(
  280. "適正表",
  281. "1D6",
  282. [
  283. "ランダムなクラス1種であること",
  284. "生まれ表でランダムに選んだジョブであること",
  285. GENDER_TABLE,
  286. "上級ジョブであること",
  287. "モンスタースキルを修得していること",
  288. "童貞、もしくは処女であること",
  289. ]
  290. )
  291. 1 ITEM_ATTRIBUTE_TABLE = ItemFeature.new(
  292. "属性表",
  293. "1D6",
  294. [
  295. "自然の力。10レベル以下の人間カテゴリのモンスターと重要NPC",
  296. "幻夢の力。10レベル以下の異形と呪物カテゴリのモンスター",
  297. "星炎の力。10レベル以下の魔獣と鬼族カテゴリのモンスター",
  298. "暗黒の力。10レベル以下の妖精と天使カテゴリのモンスター",
  299. "聖なる力。10レベル以下の死霊と深人カテゴリのモンスター",
  300. "災厄の力。支配者として設定されているキャラクター",
  301. ]
  302. )
  303. 1 class ItemFeaturesTable
  304. 1 def initialize
  305. @items = [
  306. 1 ["そのアイテムは「", ITEM_POWER_TABLE, "」の神力を宿す。"],
  307. ["そのアイテムは寿命を持つ。寿命の値を決定する。\nさらに、", self],
  308. ["そのアイテムは境界障壁を持つ。《HP》の値を決定する。"],
  309. ["そのアイテムは銘を持つ。銘を決定する。"],
  310. ["そのアイテムは合成具である。もう1つの機能は「", ITEM_RANDOM_TABLE, "」である。"],
  311. ["そのアイテムにレベルがあれば、レベルを1点上昇する。\nレベルが設定されていなければ、", self],
  312. ["そのアイテムは「", ITEM_JYUMON_TABLE, "」の呪紋を持つ。"],
  313. ["そのアイテムは「", ITEM_JYUKA_TABLE, "」の呪禍を持つ。\nさらに、", self],
  314. ["そのアイテムは高価だ。価格を設定する。"],
  315. ["そのアイテムは「条件:", ITEM_APTITUDE_TABLE, "」の適正を持つ。\nさらに、", self],
  316. ["そのアイテムは「", ITEM_ATTRIBUTE_TABLE, "」の属性を持つ。"],
  317. ].freeze
  318. end
  319. 1 def roll(randomizer)
  320. 15 dice = randomizer.roll_sum(2, 6)
  321. 15 index = dice - 2
  322. 15 chosen_row = @items[index]
  323. 15 string_list = chosen_row.map do |s|
  324. 41 case s
  325. when: 23 when String
  326. 23 s
  327. when: 8 when ItemFeature
  328. 8 s.choice(randomizer)
  329. else: 10 else
  330. 10 s.roll(randomizer)
  331. end
  332. end
  333. 15 return "特性[#{dice}]:#{string_list.join('')}"
  334. end
  335. end
  336. 1 ITEM_FEATURES_TABLE = ItemFeaturesTable.new().freeze
  337. ITEM_TABLES = {
  338. 1 "WIT" => WEAPON_ITEM_TABLE,
  339. "LIT" => LIFE_ITEM_TABLE,
  340. "RIT" => REST_ITEM_TABLE,
  341. "SIT" => SEARCH_ITEM_TABLE,
  342. "CIR" => COMMON_ITEM_RANDOM_TABLE,
  343. "NRUT" => NORMAL_RARE_ITEM_TABLE,
  344. "ARUT" => ADVANCED_RARE_ITEM_TABLE,
  345. "RUIR" => RARE_ITEM_RANDOM_TABLE,
  346. "NRWT" => NORMAL_RARE_WEAPON_ITEM_TABLE,
  347. "ARWT" => ADVANCED_RARE_WEAPON_ITEM_TABLE,
  348. "RWIR" => RARE_WEAPON_ITEM_RANDOM_TABLE,
  349. }.freeze
  350. end
  351. end
  352. end

lib/bcdice/game_system/meikyu_kingdom_basic/kingdom_table.rb

92.31% lines covered

100.0% branches covered

39 relevant lines. 36 lines covered and 3 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MeikyuKingdomBasic
  5. # 王国名決定表1(D66)
  6. # override
  7. 1 def mk_kingdom_name_1_table(num)
  8. table = [
  9. 1 [11, "暗黒、クラヤミ、星灯り、カガヤキ、シャイニング、黄昏、暁"],
  10. [12, "王政、帝政、爆発、回転"],
  11. [13, "超、スーパー、秘密主義、高等、ハイ、どん底"],
  12. [14, "共和制、立憲、公立、私立"],
  13. [15, "古代、新、ネオ、笑う、歌う"],
  14. [16, "共産、社会主義、自由、自由主義、ぶらり、ここは"],
  15. [22, "専制、民主主義、踊る、眠れる"],
  16. [23, "第三、最終、特別、標準"],
  17. [24, "神聖、聖、セント、絶対主義、現代、未来"],
  18. [25, "正統、本格、裏、偽、リバース、怪奇、幻想"],
  19. [26, "本家、元祖、荒ぶる、分かる"],
  20. [33, "大、グレート、小、スモール、必殺、淡麗"],
  21. [34, "天階、上、上方、深階、下、下方、異世界、現代"],
  22. [35, "東、東方、西、西方、かわいい、世界の"],
  23. [36, "北、北方、南、南方、赤い、緑の"],
  24. [44, "中央、辺境、飛び出せ、戦え"],
  25. [45, "独立、統一、ちはやぶる、八雲立つ"],
  26. [46, "永世、臨時、ザ、ラ"],
  27. [55, "さよなら、おはよう、太平、汎"],
  28. [56, "好戦的、平和的、素晴らしき、衝撃の"],
  29. [66, "優しい、怖い、ぼくらの、みんなの"],
  30. ]
  31. 1 return get_table_by_number(num, table)
  32. end
  33. # 王国名決定表2(D66)
  34. # override
  35. 1 def mk_kingdom_name_2_table(num)
  36. table = [
  37. 1 [11, "凸凹、仄仄、子ども、大人"],
  38. [12, "迷宮、ダンジョン、監獄、封印、墓場"],
  39. [13, "グランドゼロ、エレベータ、コンパス、行き止まり"],
  40. [14, "サイコロ、ダイス、ランダム、ファンブル、ピンゾロ、シャッフル"],
  41. [15, "災厄、征服、無敵、野蛮"],
  42. [16, "デーモン、魔神、エンジェル、天使、超人、哲人"],
  43. [22, "野球、サッカー、クリケット、バドミントン"],
  44. [23, "商、武、科学、クラフト"],
  45. [24, "ドラゴン、龍、ヴァンパイア、吸血鬼、ヒューマン、人間、フェアリー、妖精"],
  46. [25, "猫、狼、キリン、キンギョ"],
  47. [26, "バナナ、ボルシチ、スシ、チーズ"],
  48. [33, "ファンタジー、魔法、マジカル、冒険、英雄"],
  49. [34, "大砲、刀剣、装甲、鉄拳"],
  50. [35, "ひきこもり、乙女、3D、転生"],
  51. [36, "崖っぷち、片隅、路地裏、炎上"],
  52. [44, "電脳、浪漫、蒸気、退廃"],
  53. [45, "コンプライアンス、ダイバーシティ、アグリー、ウィンウィン"],
  54. [46, "ローマ、中華、エジプト、アステカ"],
  55. [55, "(単語表1で決定)、(単語表2で決定)、(単語表3で決定)、(単語表4で決定)"],
  56. [56, "(プレイ会場の地名)、(GMの出身地)、(この表を使用した者の住所)、(GMの苗字)"],
  57. [66, "(国王の名前。後で決定)、(国王のジョブ名。後で決定)、(ランダムな武具アイテム名)、(ランダムな日常アイテム名)"],
  58. ]
  59. 1 return get_table_by_number(num, table)
  60. end
  61. # 王国名決定表3(D66)
  62. # override
  63. 1 def mk_kingdom_name_3_table(num)
  64. table = [
  65. 1 [11, "王国、キングダム、王朝"],
  66. [12, "会社、公社、本舗"],
  67. [13, "学園、学校、食堂"],
  68. [14, "汗国、国"],
  69. [15, "合衆国、政府"],
  70. [16, "共同体、共和国"],
  71. [22, "司教国、教皇領"],
  72. [23, "星、伯国"],
  73. [24, "公国、大公国"],
  74. [25, "市、シティ、ポリス、都、のみやこ"],
  75. [26, "自治国、騎士団領"],
  76. [33, "植民地、統一機構"],
  77. [34, "帝国、皇国"],
  78. [35, "同盟、機関"],
  79. [36, "首長国、土侯国"],
  80. [44, "幕府、藩王国"],
  81. [45, "領、クラブ"],
  82. [46, "村、町、街"],
  83. [55, "横丁、亭、社中"],
  84. [56, "ランド、戦線"],
  85. [66, "連邦、連合"],
  86. ]
  87. 1 return get_table_by_number(num, table)
  88. end
  89. # 王国環境表(1D6)
  90. 1 def mk_kingdom_environment_table(num)
  91. 2 d1 = @randomizer.roll_once(6)
  92. functionTable = [
  93. 2 [1, lambda { mk_technic_decide_table(d1) }],
  94. [2, lambda { mk_national_style_decide_table(d1) }],
  95. [3, lambda { mk_resource_decide_table(d1) }],
  96. 1 [4, lambda { mk_facility_decide_table(d1) }],
  97. [5, lambda { mk_human_resources_decide_table(d1) }],
  98. 1 [6, lambda { mk_blood_decide_table(d1) }],
  99. ]
  100. 2 return get_table_by_number(num, functionTable)
  101. end
  102. # 技術決定表(1d6)
  103. 1 def mk_technic_decide_table(num)
  104. table = [
  105. 1 [1, "あなたの国は、魔法の研究、開発に力をそそぐ魔道国家である。その国のキャラクターは、星術、召喚、科学スキルの判定を行うとき、その達成値が1点上昇する(最大3点まで上昇する。4回目以降は振り直すこと)。"],
  106. [2, "あなたの国は、神話的遺物の逸話が残っている。レア一般アイテムの中からランダムに1種を選ぶ。そのレアアイテムのレシピを持っている。【王宮】のある部屋に、そのレア一般アイテムの名前を記入すること。"],
  107. [3, "あなたの国は、英雄が用いた武具の伝説が残っている。レア武具アイテムの中からランダムに1種を選ぶ。そのレアアイテムのレシピを持っている。【王宮】のある部屋に、そのレア武具アイテムの名前を記入すること。"],
  108. [4, "あなたの国は、有名な職人たちが揃う工業国家である。コモンアイテムを作成するとき、それらのアイテムを作成するための必要国力が1点高いものとして扱う。"],
  109. [5, "あなたの国は、質実剛健な兵士たちが揃っている。その国のキャラクターは、《配下》最大値が1人上昇する(最大2人まで上昇する。3回目以降は振り直すこと)。"],
  110. [6, "あなたの国は、過去に列強に臣従し、いまでも友好的な関係を築いている。(1D6)を振ること。1ならダイナマイト帝国、2なら千年王朝、3ならメトロ汗国、4ならハグルマ資本主義神聖共和国との関係が「友好」になる。5や6なら振り直すこと。また、その列強の列強系施設1軒を獲得する。"],
  111. ]
  112. 1 return get_table_by_number(num, table)
  113. end
  114. # 国風決定表(1d6)
  115. 1 def mk_national_style_decide_table(num)
  116. table = [
  117. 1 [1, "あなたの国は、古くからあり、伝統を重んじる気風を持つ。宮廷系施設を建設・発展するための価格が1MG軽減される(最大2MGまで軽減される。3回目以降は振り直すこと)。"],
  118. [2, "あなたの国は、広い国土と高い天井に恵まれている。居住系施設を建設するための価格が1MG軽減される(最大2MGまで軽減される。3回目以降は振り直すこと)。"],
  119. [3, "あなたの国は、夏星が豊富で、作物がたくさん収穫できる。生産系施設を建設・発展するための価格が1MG軽減される。(最大2MGまで軽減される。3回目以降は振り直すこと)。"],
  120. [4, "あなたの国は、しっかりとした規律と礼節があり、それを守る風潮がある。公共系施設を建設・発展するための価格が1MG軽減される(最大2MGまで軽減される。3回目以降は振り直すこと)。"],
  121. [5, "あなたの国は、芸術を奨励し、文化的な国民性を誇る。娯楽系施設を建設・発展するための価格が1MG軽減される(最大2MGまで軽減される。3回目以降は振り直すこと)。"],
  122. [6, "あなたの国は、物を大切にし、質素な生活を心がける気風を持つ。保管系施設を建設・発展するための価格が1MG軽減される(最大2MGまで軽減される。3回目以降は振り直すこと)。"],
  123. ]
  124. 1 return get_table_by_number(num, table)
  125. end
  126. # 資源決定表(1d6)
  127. 1 def mk_resource_decide_table(num)
  128. table = [
  129. 1 [1, "あなたの国は、過去に善政がしかれ、非常に安定している。セッション開始時の《民の声》の値が1点上昇する(最大3点まで上昇する。4回目以降は振り直すこと)。"],
  130. [2, "あなたの国は、天然の要害に囲まれており、外敵に襲われにくい。《民》が(2D6)人増加する。"],
  131. [3, "あなたの国には、名工がつくった武器がある。ランダムに選んだ武具アイテム1個を獲得する。その武具アイテムはレベル1として扱う。"],
  132. [4, "あなたの国には、先頃友誼を誓い合った同盟国がある。王国シートの周辺階域から、ランダムに未知の土地1つを選ぶ。その土地に、王国を1つ設定すること。この国は【特産物】を持つ。「相場表」を使って、【特産物】の素材をランダムに決定すること。この国との関係は「同盟」となる。"],
  133. [5, "あなたの国で先頃、前王の隠し財産が発見された。《予算》を(1D6) MG獲得する。"],
  134. [6, "あなたの国には、隠し扉があった。「自国の地理」を決定したあと、追加で通路を2本引くことができる。通路でつながっている部屋は領土として扱う。"],
  135. ]
  136. 1 return get_table_by_number(num, table)
  137. end
  138. # 施設決定表(1d6)
  139. 1 def mk_facility_decide_table(num)
  140. table = [
  141. 2 [1, "あなたの国は、その地方を代々統治する伝統ある王国だ。宮廷系施設の中からランダムに1種を選ぶ。自国にその施設を1件建設する。"],
  142. [2, "あなたの国は、交易路の周囲にあり、多くの人々が流入する。居住系施設の中からランダムに1種を選ぶ。自国にその施設を1件建設する。"],
  143. [3, "あなたの国は、職人気質のものが多く、物作りがさかんだ。生産系施設の中からランダムに1種を選ぶ。自国にその施設を1件建設する。"],
  144. [4, "あなたの国は民を第一に考え、福祉に力を入れている。公共系施設の中からランダムに1種を選ぶ。自国にその施設を1件建設する。"],
  145. [5, "あなたの国は、歓楽国家として知られ、他国からの客もよく出入りしている。娯楽系施設の中からランダムに1種を選ぶ。自国にその施設を1件建設する。"],
  146. [6, "あなたの国は、辺境に位置する王国だ。周辺には怪物も少ない。保管系施設の中からランダムに1種を選ぶ。自国にその施設を1件建設する。"],
  147. ]
  148. 2 return get_table_by_number(num, table)
  149. end
  150. # 人材決定表(1d6)
  151. 1 def mk_human_resources_decide_table(num)
  152. table = [
  153. 1 [1, "あなたの国には、高い見識を持つ知識人がいる。「才覚系生まれ表」でランダムにジョブ1種を選ぶ。そのジョブの逸材を1人獲得する。逸材の名前を決定すること。"],
  154. [2, "あなたの国には、皆を魅了する好人物がいる。「魅了系生まれ表」でランダムにジョブ1種を選ぶ。そのジョブの逸材を1人獲得する。逸材の名前を決定すること。"],
  155. [3, "あなたの国には、巧みな技術を持つ専門家がいる。「探索系生まれ表」でランダムにジョブ1種を選ぶ。そのジョブの逸材を1人獲得する。逸材の名前を決定すること。"],
  156. [4, "あなたの国には、見事な腕前の戦士がいる。「武勇系生まれ表」でランダムにジョブ1種を選ぶ。そのジョブの逸材を1人獲得する。逸材の名前を決定すること。"],
  157. [5, "あなたの国は、怪物と共存している? (1D6)を振ること。1なら【小鬼】、2なら【ウマトカゲ】、3なら【ドワーフ】、4なら【エルフ】、5なら【キンギョ】、6なら【ごんぎつね】の《モンスターの民》を(1D6)人獲得する。"],
  158. [6, "あなたの国は、ここしばらく怪物や敵国の襲撃もなく、平和な日々が続いていた。《民》が(2D6)人増加する。"],
  159. ]
  160. 1 return get_table_by_number(num, table)
  161. end
  162. # 血族決定表(1d6)
  163. 1 def mk_blood_decide_table(num)
  164. table = [
  165. 2 [1, "あなたの国は、鬼族の蹂躙を受けた歴史を持ち、混血が進んでいる。その国のキャラクターは新たにスキルを修得するとき、鬼族カテゴリの自分のレベル以下のモンスターが修得しているモンスタースキルの中から、修得するスキルを選ぶことができるようになる。"],
  166. [2, "あなたの国は、古代に迷宮から姿を消した妖精女王の末裔といわれている。その国のキャラクターは新たにスキルを修得するとき、妖精カテゴリの自分のレベル以下のモンスターが修得しているモンスタースキルの中から、修得するスキルを選ぶことができるようになる。"],
  167. [3, "あなたの国は、偉大なる古龍が迷宮と化した場所であり、その尊い血を引いているといわれる。その国のキャラクターは新たにスキルを修得するとき、魔獣カテゴリの自分のレベル以下のモンスターが修得しているモンスタースキルの中から、修得するスキルを選ぶことができるようになる。"],
  168. [4, "あなたの国は、魔階からやってきた魔王の子供たちといわれている。その国のキャラクターは新たにスキルを修得するとき、異形カテゴリの自分のレベル以下のモンスターが修得しているモンスタースキルの中から、修得するスキルを選ぶことができるようになる。"],
  169. [5, "あなたの国は、死霊術師によって死者の王国に変えられた悲劇的な過去を持つ。その国のキャラクターは新たにスキルを修得するとき、死霊カテゴリの自分のレベル以下のモンスターが修得しているモンスタースキルの中から、修得するスキルを選ぶことができるようになる。"],
  170. [6, "あなたの国は、古代の錬金術師たちによって造られた人造生命が多数使役されている。その国のキャラクターは新たにスキルを修得するとき、呪物カテゴリの自分のレベル以下のモンスターが修得しているモンスタースキルの中から、修得するスキルを選ぶことができるようになる。"],
  171. ]
  172. 2 return get_table_by_number(num, table)
  173. end
  174. end
  175. end
  176. end

lib/bcdice/game_system/meikyu_kingdom_basic/name_table.rb

84.0% lines covered

70.0% branches covered

75 relevant lines. 63 lines covered and 12 lines missed.
20 total branches, 14 branches covered and 6 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MeikyuKingdomBasic
  5. # エキゾチック名前表(D66)
  6. # override
  7. 1 def mk_name_ex_table(num)
  8. table = [
  9. 1 [11, "モアイ/スイショウドクロ"],
  10. [12, "チュパカブラ/ムベンベ"],
  11. [13, "カンフー/インヤン"],
  12. [14, "ブシドー/ミヤコ"],
  13. [15, "チャンピオン/バービー"],
  14. [16, "ウパニシャッド/ゾルゲ"],
  15. [22, "デスマーチ/インテル"],
  16. [23, "ゴッホ/ヴィクトリア"],
  17. [24, "ゾンビ/オニャンコポン"],
  18. [25, "ケロッパ/カルメン"],
  19. [26, "オーバーキル/サシミ"],
  20. [33, "ブッチャー/デヴィ"],
  21. [34, "ブロンソン/マドンナ"],
  22. [35, "ガイギャックス/エロイカ"],
  23. [36, "好きな星の名前(スピカ,オリオン)"],
  24. [44, "好きな武器の名前(エペ,フランベルジュ)"],
  25. [45, "好きな動物の名前(イタチ,パグ)"],
  26. [46, "好きな鉱物の名前(ルビィ,ヒスイ)"],
  27. [55, "好きな言葉+ドラゴン"],
  28. [56, "好きな単語表で決定する"],
  29. [66, "プレイヤーと同じ名前"],
  30. ]
  31. 1 return get_table_by_number(num, table)
  32. end
  33. # 新名前決定表
  34. 1 def mk_new_name_table
  35. 3 nick_table = "1"
  36. 3 name_table = "1"
  37. # 新名前表
  38. 3 nick_n = @randomizer.roll_once(6)
  39. 3 name_n = @randomizer.roll_once(6)
  40. 3 d1 = @randomizer.roll_d66(D66SortType::ASC)
  41. 3 d2 = @randomizer.roll_d66(D66SortType::ASC)
  42. # 二つ名分岐
  43. 3 then: 1 if nick_n <= 1
  44. 1 else: 2 nick_table = mk_nick_pr_table(d1)
  45. 2 then: 0 elsif name_n <= 2
  46. else: 2 nick_table = mk_nick_fo_table(d1)
  47. 2 then: 0 elsif name_n <= 3
  48. else: 2 nick_table = mk_nick_ou_table(d1)
  49. 2 then: 1 elsif name_n <= 4
  50. 1 else: 1 nick_table = mk_nick_ti_table(d1)
  51. 1 then: 1 elsif name_n <= 5
  52. 1 nick_table = mk_nick_ph_table(d1)
  53. else: 0 else
  54. nick_table = mk_nick_co_table(d1)
  55. end
  56. # 名前分岐
  57. 3 then: 0 if name_n <= 1
  58. else: 3 name_table = mk_name_ar_table(d2)
  59. 3 then: 1 elsif name_n <= 2
  60. 1 else: 2 name_table = mk_name_fo_table(d2)
  61. 2 then: 0 elsif name_n <= 3
  62. else: 2 name_table = mk_name_dn_table(d2)
  63. 2 then: 1 elsif name_n <= 4
  64. 1 else: 1 name_table = mk_name_pl_table(d2)
  65. 1 then: 1 elsif name_n <= 5
  66. 1 name_table = mk_name_ma_table(d2)
  67. else: 0 else
  68. name_table = mk_name_go_table(d2)
  69. end
  70. 3 output = nick_table + name_table
  71. 3 debug("output", output)
  72. 3 dice = "#{nick_n},#{name_n},#{d1},#{d2}"
  73. 3 return output, dice
  74. end
  75. # ことわざ系二つ名表
  76. 1 def mk_nick_pr_table(num)
  77. table = [
  78. 1 [11, "“九死に一生を得る”"],
  79. [12, "“風前の灯火の”"],
  80. [13, "“類は友を呼ぶ”"],
  81. [14, "“性格がいい方の”"],
  82. [15, "“三階に家なき”"],
  83. [16, "“五分の理はある”"],
  84. [22, "“危ない橋を渡る”"],
  85. [23, "“バカって言った方がバカの”"],
  86. [24, "“長いものに巻かれる”"],
  87. [25, "“火の無いところの”"],
  88. [26, "“あばたもえくぼの”"],
  89. [33, "“将を射んとせばまず”"],
  90. [34, "“氷山の一角の”"],
  91. [35, "“木乃伊取りが木乃伊になる”"],
  92. [36, "“一見の価値ありの”"],
  93. [44, "“一日の長ある”"],
  94. [45, "“遠くの親類より近くの”"],
  95. [46, "“笑う門には福来る”"],
  96. [55, "“花は桜木、人は”"],
  97. [56, "“猫に小判の”"],
  98. [66, "“(クラス名/ジョブ名)による(クラス名/ジョブ名)のための”"],
  99. ]
  100. 1 return get_table_by_number(num, table)
  101. end
  102. # 四字熟語系二つ名表
  103. 1 def mk_nick_fo_table(num)
  104. table = [
  105. [11, "“自画自賛(の)”"],
  106. [12, "“人畜無害(の)”"],
  107. [13, "“不言実行(の)”"],
  108. [14, "“痛快無比(の)”"],
  109. [15, "“外柔内剛(の)”"],
  110. [16, "“百戦錬磨(の)”"],
  111. [22, "“前代未聞(の)”"],
  112. [23, "“粉骨砕身(の)”"],
  113. [24, "“天真爛漫(の)”"],
  114. [25, "“暴飲暴食(の)”"],
  115. [26, "“意志薄弱(の)”"],
  116. [33, "“慇懃無礼(の)”"],
  117. [34, "“沈魚落雁(の)”"],
  118. [35, "“波乱万丈(の)”"],
  119. [36, "“二束三文(の)”"],
  120. [44, "“行雲流水(の)”"],
  121. [45, "“驚天動地(の)”"],
  122. [46, "“破邪顕正(の)”"],
  123. [55, "“以心伝心(の)”"],
  124. [56, "“博覧強記(の)”"],
  125. [66, "“殺人事件(の)”"],
  126. ]
  127. return get_table_by_number(num, table)
  128. end
  129. # 外見系二つ名表
  130. 1 def mk_nick_ou_table(num)
  131. table = [
  132. [11, "“もふもふの”"],
  133. [12, "“裸の”"],
  134. [13, "“猫耳の”"],
  135. [14, "“歩くと音がする”"],
  136. [15, "“緑髪の”"],
  137. [16, "“黄金(の)”"],
  138. [22, "“羽根つき(の)”"],
  139. [23, "“小さな”"],
  140. [24, "“蛇手の”"],
  141. [25, "“鉤シッポの”"],
  142. [26, "“ぎざぎざの”"],
  143. [33, "“輝ける”"],
  144. [34, "“角持ち(の)”"],
  145. [35, "“とんがり帽子の”"],
  146. [36, "“青ざめた”"],
  147. [44, "“赤目の”"],
  148. [45, "“黒衣の”"],
  149. [46, "“ねじれ声の”"],
  150. [55, "“銀の腕”"],
  151. [56, "“長靴下の”"],
  152. [66, "“ぬるぬるの”"],
  153. ]
  154. return get_table_by_number(num, table)
  155. end
  156. # 称号系二つ名表
  157. 1 def mk_nick_ti_table(num)
  158. table = [
  159. 1 [11, "“(王国名)の星”"],
  160. [12, "“(王国名)の独眼竜”"],
  161. [13, "“(王国名)の麒麟児”"],
  162. [14, "“(王国名)の虎”"],
  163. [15, "“(王国名)のマムシ”"],
  164. [16, "“(王国名)1D6天王”"],
  165. [22, "“(王国名)1D6傑”"],
  166. [23, "“(王国名)1D6銃士”"],
  167. [24, "“(王国名)10+1D6神将”"],
  168. [25, "“(王国名)2D6(兄弟/姉妹)”"],
  169. [26, "“(王国名)2D6賢人”"],
  170. [33, "“あの(クラス名/ジョブ名)”"],
  171. [34, "“最後の(クラス名/ジョブ名)”"],
  172. [35, "“メカ(クラス名/ジョブ名)”"],
  173. [36, "“殺人(クラス名/ジョブ名)”"],
  174. [44, "“カリスマ(クラス名/ジョブ名)”"],
  175. [45, "“超級(クラス名/ジョブ名)”"],
  176. [46, "“攻め(クラス名/ジョブ名)”"],
  177. [55, "“スタイリッシュ(クラス名/ジョブ名)”"],
  178. [56, "“大(クラス名/ジョブ名)”"],
  179. [66, "“鬼(クラス名/ジョブ名)”"],
  180. ]
  181. 1 return get_table_by_number(num, table)
  182. end
  183. # 名文句系二つ名表
  184. 1 def mk_nick_ph_table(num)
  185. table = [
  186. 1 [11, "“世界が嫉妬する”"],
  187. [12, "“うまい、うますぎる”"],
  188. [13, "“24時間戦える”"],
  189. [14, "“脱いでもすごい”"],
  190. [15, "“ピカピカの1年生”"],
  191. [16, "“どうあがいても絶望の”"],
  192. [22, "“ダメ絶対の”"],
  193. [23, "“すべての王国を過去にする”"],
  194. [24, "“100人乗っても大丈夫な”"],
  195. [25, "“綺麗なおねえさんが好きな”"],
  196. [26, "“食う寝る遊ぶの”"],
  197. [33, "“かわいいは正義の”"],
  198. [34, "“それにつけても”"],
  199. [35, "“お口の恋人”"],
  200. [36, "“やめられない止まらない”"],
  201. [44, "“半分はやさしさの”"],
  202. [45, "“国民的美少女”"],
  203. [46, "“プライスレスの”"],
  204. [55, "“驚きの白さの”"],
  205. [56, "“楽器のマークの”"],
  206. [66, "“パンツじゃないから恥ずかしくない”"],
  207. ]
  208. 1 return get_table_by_number(num, table)
  209. end
  210. # かっこいい系二つ名表
  211. 1 def mk_nick_co_table(num)
  212. table = [
  213. [11, "“(王国名/氷)の牙”"],
  214. [12, "“(王国名/不可視)の猟犬”"],
  215. [13, "“(王国名/暴虐)の女神”"],
  216. [14, "“(王国名/無限)の境界”"],
  217. [15, "“(王国名/偽り)の救世主”"],
  218. [16, "“(王国名/闇)の扉”"],
  219. [22, "“(王国名/暁)の凶星”"],
  220. [23, "“(王国名/災禍)の中心”"],
  221. [24, "“(王国名/始まり)の記憶”"],
  222. [25, "“(王国名/絶対)の歌声”"],
  223. [26, "“(王国名/星霜)の死神”"],
  224. [33, "“(王国名/不確定)の隠者”"],
  225. [34, "“(王国名/冥府)の番人”"],
  226. [35, "“(王国名/深淵)の使途”"],
  227. [36, "“(王国名/罪)の華”"],
  228. [44, "“(王国名/終末)の翼”"],
  229. [45, "“(王国名/絶望)の匠”"],
  230. [46, "“(王国名/鮮血)の芸術家”"],
  231. [55, "“(王国名/流星)の魔剣”"],
  232. [56, "“(王国名/漆黒)の堕天使”"],
  233. [66, "“(王国名/無貌)の悪夢”"],
  234. ]
  235. return get_table_by_number(num, table)
  236. end
  237. # 芸術系名前表(D66)
  238. 1 def mk_name_ar_table(num)
  239. table = [
  240. 1 [11, "コーラス/メロディ"],
  241. [12, "シタール/コト"],
  242. [13, "トロンボーン/ティンパニ"],
  243. [14, "マーチ/セレナーデ"],
  244. [15, "ソロ/オーケストラ"],
  245. [16, "パッソ/プリマ"],
  246. [22, "モノローグ/アポローズ"],
  247. [23, "スクリプト/カメリーノ"],
  248. [24, "アール/エピカ"],
  249. [25, "ラインズ/ムジカ"],
  250. [26, "トルバドール/リリカ"],
  251. [33, "ノベル/ラマーン"],
  252. [34, "クリーミ/ストーリア"],
  253. [35, "エッセイ/メモワール"],
  254. [36, "ジャケット/コロフォン"],
  255. [44, "デビュー/セーヌ"],
  256. [45, "タンゴ/バル"],
  257. [46, "イーゼル/パレット"],
  258. [55, "カンバス/タトゥー"],
  259. [56, "ウッドカット/キラーミカ"],
  260. [66, "ポートレイト/パノラマ"],
  261. ]
  262. 1 return get_table_by_number(num, table)
  263. end
  264. # 食べ物系名前表(D66)
  265. 1 def mk_name_fo_table(num)
  266. table = [
  267. 2 [11, "ダージリン/マンデリン"],
  268. [12, "コニャック/ピーノ"],
  269. [13, "グラス/テキーラ"],
  270. [14, "ハングオーバー/リキュール"],
  271. [15, "ブレッド/プレッツェル"],
  272. [16, "バケット/コロネ"],
  273. [22, "クロワッサン/ヤムチャ"],
  274. [23, "ヤキソバ/パッタイ"],
  275. [24, "ニョッキ/ペンネ"],
  276. [25, "ハニー/メイプル"],
  277. [26, "ガトー/フラン"],
  278. [33, "ジュレ/ソルベ"],
  279. [34, "リゾット/チマキ"],
  280. [35, "フリット/テンプラ"],
  281. [36, "カルビ/ハラミ"],
  282. [44, "ポージョ/ユーリンチー"],
  283. [45, "アイスバイン/イベリコ"],
  284. [46, "ブルスト/キシュカ"],
  285. [55, "ドリアン/キウィ"],
  286. [56, "ココ/プラム"],
  287. [66, "ガリガリ/ポテチ"],
  288. ]
  289. 2 return get_table_by_number(num, table)
  290. end
  291. # 日用品系名前表(D66)
  292. 1 def mk_name_dn_table(num)
  293. table = [
  294. 1 [11, "ファイバー/シルク"],
  295. [12, "ジーンズ/キュロット"],
  296. [13, "ガーター/ソックス"],
  297. [14, "クラヴァッテ/スカーフ"],
  298. [15, "サンダル/ハイヒール"],
  299. [16, "リング/ブローチ"],
  300. [22, "ボタン/リカーモ"],
  301. [23, "シュピーゲル/ルージュ"],
  302. [24, "オーデコロン/マニキュア"],
  303. [25, "シルクハット/サリー"],
  304. [26, "ソープ/コーム"],
  305. [33, "スツール/ソファー"],
  306. [34, "ブランケット/マクラ"],
  307. [35, "ケトル/ポット"],
  308. [36, "ゲイト/ポーチ"],
  309. [44, "ギムレット/レンチ"],
  310. [45, "シェイヴァー/シャンプー"],
  311. [46, "タオル/マスカラ"],
  312. [55, "クローゼット/クッション"],
  313. [56, "カウチ/クリップ"],
  314. [66, "スタンプ/カレンダー"],
  315. ]
  316. 1 return get_table_by_number(num, table)
  317. end
  318. # 地名系名前表(D66)
  319. 1 def mk_name_pl_table(num)
  320. table = [
  321. 2 [11, "シアトル/ヴァージニア"],
  322. [12, "デーン/ヴァーサ"],
  323. [13, "タイガ/ユルガ"],
  324. [14, "クルスク/トゥール"],
  325. [15, "アラド/モルダヴィア"],
  326. [16, "キエフ/ユークレイン"],
  327. [22, "ウガンダ/ガーナ"],
  328. [23, "ギザ/アレクサンドリア"],
  329. [24, "キリマンジャロ/ソマリ"],
  330. [25, "ガイアナ/リオ"],
  331. [26, "イグアス/アマゾン"],
  332. [33, "サンティアゴ/ナスカ"],
  333. [34, "クーロン/シャンハイ"],
  334. [35, "ベナレス/デリー"],
  335. [36, "バリ/セイロン"],
  336. [44, "ティモール/スマトラ"],
  337. [45, "トリノ/シチリア"],
  338. [46, "バスク/グラナダ"],
  339. [55, "キプロス/クレタ"],
  340. [56, "ザクセン/ケルン"],
  341. [66, "リヨン/ニース"],
  342. ]
  343. 2 return get_table_by_number(num, table)
  344. end
  345. # 機械系名前表(D66)
  346. 1 def mk_name_ma_table(num)
  347. table = [
  348. 2 [11, "ウォッチ/シーナ"],
  349. [12, "アンテナ/テレ"],
  350. [13, "グリル/バティドーラ"],
  351. [14, "ステレオ/カリヨン"],
  352. [15, "マキナ/アルマ"],
  353. [16, "ロケット/ヴィルタリオート"],
  354. [22, "ルー/フラン"],
  355. [23, "モーター/モトーレ"],
  356. [24, "ドライラート/コーチェ"],
  357. [25, "クロック/セニャーレ"],
  358. [26, "ポンプ/アントリア"],
  359. [33, "スケイルズ/プランチャ"],
  360. [34, "ランプ/シャンデリア"],
  361. [35, "ガジエラ/カノン"],
  362. [36, "リフト/エクレール"],
  363. [44, "ナルキ/プランタ"],
  364. [45, "サカプンタス/アーラ"],
  365. [46, "シュレッダー/ナウス"],
  366. [55, "ファブリーク/ユジーヌ"],
  367. [56, "ボイラー/カルダイヤ"],
  368. [66, "エンジン/トリシクル"],
  369. ]
  370. 2 return get_table_by_number(num, table)
  371. end
  372. # 神様系名前表(D66)
  373. 1 def mk_name_go_table(num)
  374. table = [
  375. 1 [11, "ケルヌンノス/アリアンロッド"],
  376. [12, "ジーザス/マリア"],
  377. [13, "ブッダ/スジャータ"],
  378. [14, "ゼウス/ヘラ"],
  379. [15, "シヴァ/パールヴァティ"],
  380. [16, "マルス/ミネルヴァ"],
  381. [22, "スサノオ/ウズメ"],
  382. [23, "バンコ/ジョカ"],
  383. [24, "インティ/パチャママ"],
  384. [25, "ダグザ/モリガン"],
  385. [26, "バロン/ランダ"],
  386. [33, "アヌビス/バステト"],
  387. [34, "ジャンゴ/アナンシ"],
  388. [35, "トラロック/コアトリクエ"],
  389. [36, "バアル/アシュタルテ"],
  390. [44, "アフラマズダ/アムルタート"],
  391. [45, "ベロボーグ/モコシ"],
  392. [46, "エンキ/イナンナ"],
  393. [55, "オーディン/フレイヤ"],
  394. [56, "ココペリ/ココペルマナ"],
  395. [66, "クトゥルフ/ハイドラ"],
  396. ]
  397. 1 return get_table_by_number(num, table)
  398. end
  399. end
  400. end
  401. end

lib/bcdice/game_system/meikyu_kingdom_basic/table.rb

100.0% lines covered

100.0% branches covered

4 relevant lines. 4 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MeikyuKingdomBasic
  5. TABLES = {
  6. 1 "TBT" => DiceTable::Table.new(
  7. "才覚休憩表",
  8. "2D6",
  9. [
  10. "寝付けないので、民と噂話に花を咲かせる。すると、経費削減のアイデアが……。[才覚/9]の判定を行う。成功すると、このセッションの《維持費》を(1D6)MG減少できる。",
  11. "自分の嫌いなものに追い回される夢を見る。心寂しくなったところに、仲間が様子を見に来てくれた。宮廷の中からキャラクター1人を選ぶ。そのキャラクターへの《好意》+1。",
  12. "好きなものの夢を見る。鳴呼、もっと……もっと……。好きなもの1つを選ぶ。その好きなものに関する幸せそうなシチュエーションを考え、他のプレイヤーやGMに伝える。その夢が幸せそうだと感じる者がいたら、《気力》+2。",
  13. "さて一眠りするか……というときに、1人の民が青い顔をして震えている。どうやら、 国に残した家族のことが心配なようだ。[才覚/11]の判定を行う。成功すると、《民の声》+2。",
  14. "「もう少しだ。頑張ろう」あなたは、あらん限りの力をこめて、仲間に呼びかけた。[才覚/9]の判定を行う。成功すると、宮廷のキャラクターは《気力》を1点ずつ消費できる。消費した《気力》と合計値だけ《民の声》が回復する。",
  15. "配下や仲間たちに指示を出し、休憩中も休む暇なく働く。くたくたになって、あくびをすると配下がお茶を差し入れてくれた。《民の声》+1。",
  16. "地図を前にして、今後の冒険について口角泡を飛ばす。意見の対立はあったが、あなたの意見が通った。我々に必要なのは英雄的死亡ではなく、卑劣な生存なのだ。 宮廷の好きなキャラクター1体を選ぶ。そのキャラクターの自分に対する《敵意》を好きなだけ上昇させ、上昇した値だけ《民の声》を回復する。",
  17. "たまには、わたしが料理してみるか……。【お弁当】か【フルコース】の効果を使用して、食事をとることができる。食事をしたら、(1D6)を振る。奇数だったら思いのほか美味しい出来映え。《民の声》+1。偶数だったら腹にはたまるが二度とごめんという出来映え。宮廷全員のあなたに対する《敵意》+1。",
  18. "配下の中でも年若い者たちがあなたの周りに群がり、冒険の話を聞かせてくれとせがむ。[才覚/現在の《民の声》の値+3] の判定を行う。成功すれば、《民の声》+(1D6)。失敗すると、次の1クォーターは行動ができない。",
  19. "迷宮に囚われた哀れな人々を見つける。助けたいのはやまやまだが、食料がやや心配だ。[才覚/9]の判定を行う。成功すると、自分の《配下》+(1D6)人。",
  20. "「やはりな……」迷宮は予想通り、一筋縄ではいかないようだ。こんなときこそ、準備しておいたアレが役に立つ。自分の修得しているスキル1種を選ぶ。そのスキルを喪失して、そのスキルと同じスキルグループのスキル1種を修得してもよい。この効果は永続する。",
  21. ]
  22. ),
  23. "CBT" => DiceTable::Table.new(
  24. "魅力休憩表",
  25. "2D6",
  26. [
  27. "妖精のワイン蔵を発見、酒盛りが始まる。宮廷全員の《気力》+1。[魅カ/9]の判定に失敗すると、酔っ払ったあなたは服を脱ぎはじめる。(1D6)を振る。自分を除く宮廷全員のあなたに対する《感情値》+1、奇数ならその属性が《好意》、偶数なら《敵意》になる。",
  28. "「実はわたし……むにゃむにゃむにゃ」休憩中、意外な寝言を言ってしまう。自分を除く宮廷全員は、自分に対する《好意》と《敵意》を反転させることができる。",
  29. "休憩中、冷たい床があなたの体温を奪っていく。あなたは、無意識のうちにぬくもりを求め、体を寄せ合う。あなたに《好意》を持っているキャラクターの数だけ、《気カ》と《HP》が回復する。",
  30. "こっそり2人で抜け出していい雰囲気に。その部屋の中に、自分と好きなものが同じキャラクターがいれば、そのキャラクター1体を選び、互いに対する《好意》+1。",
  31. "星の灯りがあなたの顔をロマンチックに照らし出す。その部屋にいる人物の中から好きなキャラクター1人を選び、[魅力/9+そのキャラクターのあなたに対する《好意》]の判定を行う。成功すると、そのキャラクターのあなたに対する《好意》+1。",
  32. "あいつと目が合う。[魅力/9]の判定を行う。成功したら、自分以外の宮廷の中から、ランダムにキャラクター1体を選ぶ。そのキャラクターから自分に対する《好意》か、自分からそのキャラクターに対する《好意》かのいずれかが1点上昇する。",
  33. "見張りの途中にうたた寝。目を覚ますと、誰かが毛布をかけてくれていた。ランダムにキャラクターを選ぶ。自分のそのキャラクターに対する《好意》+1。",
  34. "野営に最適な場所を見つける。たき火を囲みながら、思い思い会話を楽しむ。GMの左隣にいるプレイヤーから順番に、自分のPCが《好意》を持っているキャラクター1体を選ぶ。選ばれたキャラクターは、《気力》+1。誰からも選ばれなかったキャラクターは《気力》-1、宮廷の中からランダムにキャラクター1体を選ぶ。そのキャラクターに対する《敵意》+1。",
  35. "疲れた体を癒やすため、テントの中で楽な衣装に着替えよう。するとそこに侵入者が……。宮廷からランダムにキャラクターを1人選び(1D6)を振る。奇数ならあなたは大声を出し、宮廷全員のそのキャラクターに対する《敵意》+1。偶数ならそのキャラクターとあなたの互いに対する《好意》+1。",
  36. "部屋のすみに隠れていた怪物が現れた! すぐには襲いかかってこないようだが……。[魅力/10]の判定を行う。成功すれば怪物と友好関係を結ぶことができる。自分のレベル以下のモンスター1体を選び、そのモンスターが自分の《配下》になる。失敗すると、モンスターに襲われる。宮廷全員の《HP》が(1D6)点減少する。",
  37. "ふとした拍子に唇が触れあう★ 好きなキャラクター1体を選ぶ。そのキャラクターの自分以外に対する《好意》を合計し、その値を自分に対する《好意》に加える。その後、そのキャラクターの自分以外に対する《好意》をすべて0にする。",
  38. ]
  39. ),
  40. "SBT" => DiceTable::Table.new(
  41. "探索休憩表",
  42. "2D6",
  43. [
  44. "一休みする前に道具の手入れ。使い慣れた道具ほど手になじむ。ランダムに自分の装備しているアイテム1つを選ぶ。そのアイテムのレベルが1上昇する。",
  45. "寝床を探していたら、アルコーブがあり、その奥に宝箱をみつける。[探索/9]の判定を行う。成功すると、好きな素材1種類を選び、それを(1D6)個獲得する。",
  46. "民が寝静まったあと、あなたも一眠り。するとその夢の中で……。[探索/11]の判定を行う。成功したら、好きな部屋を指定する。その部屋の脅威情報を、GMから教えてもらうことができる。 ",
  47. "配下が眠りにつき、部屋が静寂に包まれると、隣の部屋から妙な音が聞こえる。この部屋に隣接する好きな部屋1つを選ぶ。[探索/9]の判定に成功すると、その部屋のモンスターの種類と数が分かる。",
  48. "一休みしようと思ったら、モンスターの墓場を発見! みんなで捜索だ。好きな素材を1種類選ぶ。宮廷全員の中で、あなたに対する《好意》の合計値だけ、その素材が手に入る。",
  49. "この部屋はなぜか落ち着く。もしも、その部屋の中にあなたの好きなものがあれば、《気力》を(1D6)点回復することができる。あなたはGMにその部屋に自分の好きなものがないか質問してもよい。",
  50. "壁に描かれた奇妙な壁画が、あなたを見つめているような気がする……。[探索/9]の判定を行う。成功すると、【エレベータ】を発見する。",
  51. "白骨化した先客の死体が見つかる。使えそうな装備は、ありがたく頂戴しておこう。[探索/10]の判定を行う。成功したら、コモンアイテムのカテゴリの中から好きなもの1つを選び、その中からランダムに決めたアイテム1個を手に入れる。",
  52. "星の灯りで地図を眺める。この部屋の構造からすると、この辺りに何かあるはずなんだが……? [探索/10]の判定に成功すると、この部屋に仕掛けられたイベント型のトラップをすべて発見する。",
  53. "自然の呼び声。休んでいる間にトイレにいきたくなった……。[探索/10]の判定を行う。成功すると、その部屋に迷宮のほころびを見つける。このセッションの間、この部屋から迷宮の外に帰還することができる。",
  54. "こ、これは秘密の扉!? [探索/11]の判定を行う。成功すると、この部屋に隣接する好きな部屋に通路を伸ばすことができる。",
  55. ]
  56. ),
  57. "VBT" => DiceTable::Table.new(
  58. "武勇休憩表",
  59. "2D6",
  60. [
  61. "時が満ちるにつれ、闘志が高まる。現在の経過ターン数と等しい値だけ、《気力》が回復する。",
  62. "もっと……もっと敵と戦いたい。血に飢えた自分を発見する。[武勇/9]の判定を行う。成功すると、《気力》+1、《HP》が(1D6)点回復する。",
  63. "部屋の片隅にうち捨てられたむごたらしい亡骸を発見する。このマップの支配者の名前が分かっていれば、宮廷全員、このマップの支配者への《敵意》+1できる。",
  64. "部屋のすみに隠れていた怪物が、休憩中の民に襲いかかる! あなたは、咄嗟に武器を手にし、怪物たちに躍りかかった! [武勇/9]の判定を行う。成功すれば怪物を追い払い、《民の声》+1。失敗すると、自分の《配下》-(1D6)人、《民の声》-1。",
  65. "危ない! 短剣があなたの横をかすめる。すると、そこにはあなたに躍りかかろうとしていた毒蛇が。もしかして、アイツのことを誤解していたかも……。自分が《敵意》を持っているキャラクター1体を選び、そのキャラクターに対する《好意》+2。",
  66. "少し見ないうちに、恐るべき実力を身につけている。今のうちに潰しておくか……。あなたの中にドス黒い気持ちがわき上がる。名前を知っているキャラクター1体を選び、そのキャラクターへの《敵意》+1。",
  67. "ちょっとした行き違いから、軽い口論になってしまう。宮廷の中からランダムにキャラクターを1体選ぶ。そのキャラクターとあなたの互いに対する《敵意》+1。",
  68. "ライバルの活躍が気になる。宮廷全員の中で、あなたに対する最も高い《敵意》の値と同じだけ《気力》を獲得する。",
  69. "休むときに休まなければ、いざというときに戦えない。他の仲間にまかせて、しっかりと体を休めることにする。《HP》を(2D6)点回復することができる。",
  70. "この足跡は……もしや? 怪物のいた痕跡を発見する。[武勇/10]の判定を行う。成功すると、このゲームで遭遇する予定のまだ種類の分かっていないモンスターを1種類、GMから教えてもらうことができる。",
  71. "……殺気! あなたは、毛布をはねのけ、戦闘態勢を整えるよう指示した。「特殊遭遇表」を1回使用し、その後、好きな素材を(1D6)個獲得する。さらに、ランダムにレアアイテム1種を選び、それを手に入れる。",
  72. ]
  73. ),
  74. "THT" => DiceTable::Table.new(
  75. "才覚ハプニング表",
  76. "2D6",
  77. [
  78. "自分に王国を導くことなど可能なのだろうか……。【お酒】を1個消費することができなければ、このセッションの間、[才覚]-1。",
  79. "国王の威信が問われる。(2D6)を振り、その値が[《民の声》+宮廷全員の国王に対する《好意》の合計]以上だった場合、《民の声》-(1D6)、さらにもう1度(2D6)を振って、才覚ハプニング表の効果を適用する。",
  80. "思考に霧の帳が降りる。「散漫2」の変調を受ける。",
  81. "重大な裏切りを犯してしまう! あなたに対する《好意》が最も高いキャラクターを1人選ぶ。そのキャラクターのあなたに対する《感情値》を《敵意》に反転させる。",
  82. "この人についていっていいのだろうか……? 宮廷全員のあなたに対する《好意》-1(0未満にはならない)。その結果、誰かの《好意》が0になると《民の声》-1。",
  83. "宮廷のスキャンダルが暴露される! 宮廷全員のあなたに対する《敵意》の中で、最も高い値と同じだけ《民の声》が減少する。",
  84. "あなたの失策が近隣で噂になる。近隣の国からランダムに国を1つ選ぶ。その国との関係が1段階悪化する。",
  85. "王国の経済に破綻の危険が発見される。[生活レベル/9+現在の経過ターン数]の判定を行う。失敗すると、維持費が(1D6)MG上昇する。",
  86. "この区画一帯の疲労が一層激しくなる。1クォーターが経過する。",
  87. "逸材の賃上げ要求が始まる。終了フェイズの予算会議のとき、[今回使用した逸材の数×1]MGだけ維持費が上昇する。",
  88. "今の自分に自信が持てなくなる。生まれ表からランダムにジョブを1つ選び、現在のジョブをそのジョブに変更する。",
  89. ]
  90. ),
  91. "CHT" => DiceTable::Table.new(
  92. "魅力ハプニング表",
  93. "2D6",
  94. [
  95. "民同士のいさかいに心を痛め、頭髪にダメージが! 【お酒】を1個消費することができなければ、このセッションの間、[魅力]-1。",
  96. "あなたの何気ない一言が不和の種に……。好きなキャラクター1人選ぶ。そのキャラクターに対する宮廷全員の《敵意》+1。",
  97. "あなたの美しさに嫉妬した迷宮が、あなたの姿を変える。「呪い3」の変調を受ける。",
  98. "可愛さあまって憎さ百倍。あなたに対する《好意》が最も高いキャラクターを1人選ぶ。そのキャラクターのあなたに対する《感情値》を《敵意》に反転する。",
  99. "あなたをめぐって不穏な空気……。宮廷全員のあなたに対する愛情の《好意》を比べ、上から2人を選ぶ。その2人の互いに対する《敵意》+1。",
  100. "いがみ合う宮廷の面々を見て、民の士気が減少する。宮廷全員のあなたに対する《敵意》の中で、最も高い値と同じだけ、自分の《配下》が減少する。",
  101. "宮廷に嫉妬の嵐が巻き起こる。宮廷の中で、あなたに対して《好意》を持つキャラクターの数を数える。このセッションの間、行為判定を行うとき、サイコロの目の合計がこの数以下だった場合、絶対失敗となる(2未満にはならない)。",
  102. "愛想をつかされる。宮廷全員のあなたに対する《好意》-1(0未満にはならない)。",
  103. "あなたの指揮に疑問を訴える者が……。[魅力/自分の《配下》の値×1]の判定を行う。失敗した場合、[難易度-達成値]人の《配下》が減少する。",
  104. "あなたの恋人だという異性が現れる! 宮廷全員のあなたに対する《好意》を比べ、最も高いキャラクターを1人選ぶ。そのキャラクターの[武勇]の値と同じだけ《HP》を減少する。",
  105. "他人が信用できなくなる。このセッションの間、協調行動を行えなくなる。",
  106. ]
  107. ),
  108. "SHT" => DiceTable::Table.new(
  109. "探索ハプニング表",
  110. "2D6",
  111. [
  112. "指の震えが止まらない……。【お酒】を1個消費することができなければ、このセッション中、[探索]-1。",
  113. "流れ星に直撃。《HP》-(1D6)。",
  114. "敵の過去を知り、相手に同情してしまう。あなたは、このマップの支配者に対する《好意》+1。このセッションの間、《好意》を持ったキャラクターに対して攻撃を行い、絶対失敗した場合、その《好意》の値だけ《気力》が減少する。",
  115. "昨日の友は今日の敵。あなたに対する《好意》が最も高いキャラクターを1人選ぶ。そのキャラクターのあなたに対する《感情値》を《敵意》に反転する。",
  116. "うっかりアイテムを落として壊してしまう。ランダムにアイテムスロットを1つ選ぶ。そのスロットにアイテムが入っていれば、そのアイテムをすべて破壊する。",
  117. "カーネルが活性化し、トラップが強化される。このセッションの間、トラップを解除するための難易度+1。",
  118. "友情にヒビが! 宮廷全員のあなたに対する《敵意》+1。",
  119. "敵の疲労攻撃! 宮廷全員は[探索/11]の判定を行う。失敗したキャラクターは(2D6)点のダメージを受ける。",
  120. "つい出来心から、国費に手を出してしまう。GMは好きなコモンアイテム1つを選ぶ。そのキャラクターはそのアイテムを入手するが、維持費+(1D6)、《民の声》-1。同じ部屋に別のPCがいれば、《希望》1点消費し、[探索/9]の判定に成功すればそれを止めることができる。",
  121. "封印されていたトラップを作動させてしまう。ランダムに災害系トラップの中から1つ選ぶ。そのトラップが発動する。",
  122. "あなたを憎む迷宮支配者が、あなたの首に賞金をかけた。このセッションの間、モンスターの攻撃やトラップの目標をランダムに決める場合、その目標は必ずあなたになる(この効果を2人以上が受けた場合、この効果を受けた者の中でランダムに決定する)。",
  123. ]
  124. ),
  125. "VHT" => DiceTable::Table.new(
  126. "武勇ハプニング表",
  127. "2D6",
  128. [
  129. "つい幼児退行を起こしそうになる。【お酒】を1個消費することができなければ、このセッション中、[武勇]-1。",
  130. "バカな! 不意打ちか!? 次に行う戦闘は奇襲扱いとなる。",
  131. "配下の期待が、あなたの重荷となる。[現在の《民の声》-1D6]点だけ《気力》が減少する。",
  132. "「あ、危ないッ!」配下があなたをかばう! 自分の《配下》-(1D6)。",
  133. "ムカついたので思わず殴る。自分の《敵意》の中で、最も高いキャラクターをランダムに1人選ぶ。そのキャラクターの《HP》が、自分の[武勇]と等しい値だけ減少する。",
  134. "決闘だッ! 宮廷全員のあなたに対する《敵意》の中で、最も高い値を選ぶ。その値の分だけ、あなたの《HP》が減少し、《気力》+2。",
  135. "豚どもめ……。宮廷全員に対する《敵意》+1。",
  136. "古傷が痛み出す。このセッションの間、戦闘であなたに対する敵の攻撃が成功すると、常に1点余分にダメージを受ける。",
  137. "不意に絶望と虚無感が襲い、あなたたちの心が折れる。宮廷全員の《気力》-1。",
  138. "あなたの親の仇を名乗るものたちが現れた。ランダムにセッション中に倒したモンスターの中から1種類を選ぶ。そのモンスター(1D6)体と戦闘を行うこと。",
  139. "自分の失敗が許せない。このセッションの間、《器》が1点減少したものとして扱う。",
  140. ]
  141. ),
  142. "KDT" => DiceTable::Table.new(
  143. "王国災厄表",
  144. "2D6",
  145. [
  146. "王国の悪い噂が蔓延する。既知の土地にある他国との関係が、すべて1段階悪化する。",
  147. "自国のモンスターが凶暴化する! 自国の《モンスターの民》の中からランダムに1種類のモンスターを選ぶ。自国の《民》を[そのモンスターのレベル]人減少する。また、そのモンスターと同じ種類の《モンスターの民》は、すべて王国からいなくなる。",
  148. "王国に疫病が大流行……。自国に残した《民》を[自国に残した《民》の数×1/10]人減少する。",
  149. "自国の疲労が進行する。自国の領土のマップ数と等しい値のMGだけ維持費が上昇する。",
  150. "敵国のテロリズムが横行! [治安レベル/9]の判定を行う。失敗すると、ランダムに選んだ施設1件が破壊される。",
  151. "敵国の襲来! あなたがたの留守を狙って、敵国が同盟を結んで奇襲を行う。[軍事レベル/9]の判定を行う。失敗すると、ランダムに選んだ自国の領土1つを失う。",
  152. "敵国が陰謀を仕掛けてくる。[文化レベル/9]の判定を行う。失敗すると、ランダムに選んだ逸材1人を失う。",
  153. "食糧危機が発生! [生活レベル/9]の判定を行う。失敗すると、自国に残した《民》を[自国に残した《民》×1/5]人減少する。王国にある「肉」の素材1個を消費するたびに、《民》の減少を5人軽減することができる。",
  154. "王国が何者かに呪われる。このセッションの間、国力を使った行為判定で選んだ(2D6)の目が3以下だと、絶対失敗になる。",
  155. "極地的な迷宮津波が発生。ランダムに自国の領土のマップ1つを選ぶ。その後、既知の土地の中からランダムに土地1つを選ぶ。その2つの場所を入れ替える。",
  156. "敵国の勢力が強大化する。GMは、関係が敵対の国すべてについて、その国の領土に接する好きな土地1つを選ぶ。その土地をその国の領土にする。",
  157. ]
  158. ),
  159. "KCT" => DiceTable::Table.new(
  160. "王国変動表",
  161. "2D6",
  162. [
  163. "列強のプロパガンダが現れる。(1D6)を振り、その目が現在の《民の声》以下で、現在列強の属国になっていたら属国から抜けることができる。上回っていたら、ランダムに列強を1つ選びその属国になる。",
  164. "冒険の成功を祝う民たちが出迎えてくれる。《民の声》+2。この結果を出したプレイヤー以外の全員は、今回の冒険を振り返り当プレイヤーのPCが《好意》を得るとしたら誰が一番ふさわしいかを協議する。決定したキャラへのPCの《好意》+1",
  165. "唐突な奇襲。周辺階域の中からランダムに自国の領土を選び[軍事レベル/9]の判定を行う。成功すれば(1D6)MG獲得。失敗すると選ばれた領土の入口から順番に通路を辿り失われる部屋を([王国レベル+1]D6)個選ぶ。(同じ部屋は2度選べない)。失われた部屋の施設と部屋につながる道が全て破壊される。その部屋からすべての部屋がなくなり、終了フェイズで入口が1個もなければ自国の領土でなくなる。",
  166. "民の労働の結果が明らかに。[生活レベル/9]の判定に成功すると《予算》が自国の領土のマップ数と同じだけ増える。失敗したら《予算》が同じだけ減る。",
  167. "あなたの活躍を耳にした者たちがやってくる。シナリオの目的を満たしている場合、関係が良好・同盟の国の数だけ(1D6)を振り、[合計値+治安レベル]人だけ《民》が増える。",
  168. "王国の子どもたちがあなた方を見て成長する。』《民》が([王国に残した《民》の数÷10+治安レベル]D6)人増える。",
  169. "民は領土を渇望していた。5MGを支払えば、隣接する未知の土地1つを領土にできる。(1D6)を振り、その数だけ通路を引くことができる。通路でつながっていない部屋は自国の領土として扱わない。",
  170. "街の機能に異変が!? [治安レベル/9]の判定に成功すると、自国の好きな施設1軒を選び、その施設のレベルを1点上昇する。失敗したら、自国のタイプ:部屋の施設をランダムに1軒選び、破壊する。",
  171. "王国同士の交流が行われた。[文化レベル/9]の判定に成功すると、生まれ表でランダムにジョブを決めた逸材が1人増え、好きな国1つとの関係を1段階良好にする。失敗すると、自国の逸材1人を選んで失い、ランダムに決めた国1つとの関係が1段階悪化する。",
  172. "ただ無為に時が過ぎていたわけではない。冒険フェイズで過ごした1ターンにつき予算が1MG増える。",
  173. "民の意識が大きく揺れる。(1D6)を振り、その目が現在の《民の声》以下だったら、好きな国力を選び基本値が1点上昇する(基本値を3点以上にはできない)。出目が上回っていたら、好きな国力が1点減少する。",
  174. ]
  175. ),
  176. "CAT" => DiceTable::Table.new(
  177. "痛打表",
  178. "2D6",
  179. [
  180. "あなたの攻撃の手応えが、武器に刻まれる。その攻撃に使用した武具アイテムのレベルが1点上昇する。",
  181. "電光石火の一撃。攻撃の処理が終了した後、もう一度、行動を行うことができる。",
  182. "凄まじい一撃は、相手の姿形を変えるほどだ。攻撃目標に「呪い4」の変調を与える。",
  183. "乾坤一擲! その攻撃のダメージを算出したあと、それをさらに2倍にすることができる。",
  184. "凄まじい威力で相手を吹き飛ばす。攻撃目標を好きなエリアに移動させる。",
  185. "会心の一撃!! ダメージが(1D6)点上昇する。",
  186. "敵の勢いを利用し、大ダメージ! ダメージが攻撃目標のレベルと同じ値だけ上昇する。",
  187. "あと1歩まで追い詰める。ダメージを与える代わりに、攻撃目標の残り《HP》を(1D6)点にすることができる。",
  188. "狙いが的中! 敵の技を封じる! 攻撃目標のスキル1種を選ぶ。その戦闘の間、そのスキルを喪失させる。",
  189. "怒りの一撃! ダメージが(2D6)点上昇する。",
  190. "敵の急所をとらえ、一撃のもとに斬り伏せる。攻撃目標の《HP》を0点にする。",
  191. ]
  192. ),
  193. "FWT" => DiceTable::Table.new(
  194. "致命傷表",
  195. "2D6",
  196. [
  197. "圧倒的な攻撃が、急所を貫く。死亡する。",
  198. "致命的な一撃が、頭をかすめる。[探索/5+受けたダメージ]の判定に成功すると、行動不能になる。判定に失敗すると、死亡する。",
  199. "昏睡し、体中から血と生命の息吹が失われつつある。行動不能になる。この戦闘が終了するまでに《HP》を1点以上にしないと、そのキャラクターは死亡する。",
  200. "頭を強くうちつけ、昏睡している。行動不能になる。このクォーターが終了するまでに《HP》を1点以上にしないと、そのキャラクターは死亡する。",
  201. "重傷を負い、意識を失う。行動不能になる。(1D6)クォーターが経過するまでに《HP》を1点以上にしないと、そのキャラクターは死亡する。",
  202. "すさまじい一撃に意識を失う。行動不能になる。",
  203. "偶然、アイテムが衝撃からキミを護る。装備しているアイテムから、ランダムに1つを選ぶ。そのアイテムを破壊し、ダメージを無効にする。もし、破壊できるアイテムを1つも装備していないと行動不能になる。",
  204. "《民》たちが、その身を犠牲にしてキミを護る。自分の《配下》を(2D6)人減少し、ダメージを無効にする。もし、《配下》が1人もいなければ、行動不能になる。",
  205. "根性で攻撃を跳ね返す! [探索/5+受けたダメージ]の判定を行う。成功すると、《HP》が1点になる。失敗すると、行動不能になる。",
  206. "精神力だけで耐え忍ぶ。[武勇/5+受けたダメージ]の判定を行う。成功すると、《HP》が1点になる。失敗すると、行動不能になる。",
  207. "幸運なことに、ダメージは避けられる。しかし、ランダムに変調1つを選び、それを受ける。数値がある場合、3になる。",
  208. ]
  209. ),
  210. "CFT" => DiceTable::Table.new(
  211. "戦闘ファンブル表",
  212. "2D6",
  213. [
  214. "敵に援軍が現れる! 敵軍の中でもっともレベルの低いモンスターが(1D6)体増える。モンスターがこの結果になった場合、好きなPCの《配下》が(1D6)体上昇する。",
  215. "敵の士気がおおいに揺らぐ。自軍のキャラクター全員は1マス後退する。",
  216. "勢いあまって仲間を攻撃! 自分のいるエリアの中から、ランダムに自軍キャラクター1人を選ぶ。そのキャラクターに使用している武器と同じ威力のダメージを与える。",
  217. "つい仲間と口論に。自軍の未行動のキャラクターの中からランダムに1人選ぶ。そのキャラクターが行動済みになる。",
  218. "馬鹿な! 魔法の効果が! 自軍のキャラクターが使用したスキルやアイテムの効果で、その戦闘の間持続するものが、全て無効になる。",
  219. "いてててて。自分を傷つけてしまう。自分に(1D6)点ダメージ。",
  220. "自分の攻撃の勢いを利用され、相手の反撃を受ける。自分の《HP》を現在の値の半分にする。",
  221. "おおっと、アイテムを落っことした。自分が装備しているアイテムからランダムに1個を選ぶ。そのアイテムが破壊される。モンスターの場合、自分に(1D6)ダメージ。",
  222. "激しい戦いに、カーネルが活性化。戦闘系トラップからランダムに1種類を選ぶ。その場に、トラップが配置される。",
  223. "あなたの攻撃は空をきり、絶望に囚われる。自分と、自分に対して1点以上《好意》を持ったキャラクター全員の《気力》-1 。モンスター側の場合、自分に(1D6)点ダメージ。",
  224. "あっ! 武器がすっぽぬけた。攻撃に使用していたアイテムが破壊される。モンスターの場合、自分に(1D6)点ダメージ。さらに、戦場シートにいるキャラクターの中からランダムにキャラクター1体を選ぶ。そのキャラクターの《HP》が1点になる。",
  225. ]
  226. ),
  227. "TT" => DiceTable::Table.new(
  228. "道中表",
  229. "2D6",
  230. [
  231. "道中の時間が、人間関係に変化をもたらす。全員、好きなキャラクター1人を選ぶ。そのキャラクターに対する《感情値》が1点上昇する。",
  232. "ん? 何かの死体が転がっている。好きな素材1種類を選ぶ。宮廷のPC1人は、その素材を(1D6)個手に入れる。",
  233. "カーネルの異常が発生し、あたりが闇に包まれる。宮廷の中から、ランダムにPC1人を選ぶ。そのPCが【星の欠片】を持っていたら、それが1個破壊される。",
  234. "迷宮災厄のせいか、道に迷いそうになる。全員、[才覚/9]の判定を行う。[(1D6)-成功したPCの数]クォーターの時間が経過する(0クォーター未満にはならない)。",
  235. "陰湿なトラップにひっかかる。全員、[探索/9]の判定を行う。失敗したPCは、《HP》を(1D6)点減少する。",
  236. "迷宮は不気味に静まり返っている……。特に何も起こらなかった。",
  237. "モンスターの襲撃を受ける。全員、[武勇/9]の判定を行う。失敗したPCは、《HP》を(1D6)点減少する。",
  238. "恐ろしげな咆哮があたりに響き、すぐに静まり返る。全員、[魅力/9]の判定を行う。失敗したPCは、《配下》が(1D6)人自国に逃走する。",
  239. "迷宮災厄発生! 気がつくと自分たちの王国に戻っていた。",
  240. "を? 何かが落ちてるぞ。ランダムにコモンアイテム1個を選ぶ。そのアイテムを手に入れる。",
  241. "ラッキー♪ 1MGを拾った。",
  242. ]
  243. ),
  244. "NT" => DiceTable::Table.new(
  245. "交渉表",
  246. "2D6",
  247. [
  248. "中立的な態度は偽装だった。彼らは油断をついて不意打ちを行う。奇襲扱いで戦闘を行うこと。",
  249. "交渉は決裂! 戦闘を行うこと。",
  250. "交渉は決裂! 戦闘を行うこと。",
  251. "「贄をささげれば話を聞こう」モンスターの中でもっともレベルが高いもののレベルと等しい数だけ《配下》を消費すれば、モンスターたちは友好的になる。ただし《民の声》を(1D6)点減少する。《配下》を消費しない場合、戦闘を行うこと。",
  252. "「……お前の趣味、なに?」好きな単語表1個を選び、(D66)を振る。宮廷の中に、その項目を好きなものにしているPCがいれば、モンスターたちは友好的になる。そうでなければ、戦闘を行うこと。",
  253. "怪物たちは、物欲しそうにこちらを見ている。「肉」の素材をモンスターの数だけ消費するか、【お弁当】、【フルコース】1個を消費すれば、モンスターたちは友好的になる。消費しなければ、戦闘を行うこと。",
  254. "怪物たちは、値踏みするようにこちらを見ている。維持費を(1D6)MG上昇させれば、モンスターたちは友好的になる。上昇させなければ、戦闘を行うこと。",
  255. "「何かいいもんよこせ」モンスターの中でもっともレベルが高いもののレベル以上の価格のアイテムを消費すれば、モンスターたちは友好的になる。レアアイテムは、()内の数字に10を足したものとして考える。それを渡せなければ、戦闘を行うこと。",
  256. "「面白い話を聞かせろよ」怪物たちは、面白い話を要求してきた。プレイヤーたちは、モンスターたちが興味のありそうな話を聞かせること。GMはその話を聞いて面白いと思えば、宮廷の代表に[魅力/9]の判定を行わせること。成功した場合、モンスターたちは友好的になる。失敗した場合、戦闘を行うこと。",
  257. "「俺に勝てたら話を聞いてやろう」怪物が一騎打ちを申し込んできた。宮廷の代表は[武勇/モンスターの中で最も高い[武勇]+7]の判定を行う。判定に成功すると、モンスターたちは友好的になる。失敗すると、判定を行った者が《HP》を(1D6)点減少した後、全員で戦闘を行うこと。",
  258. "運命の出会い。一目見た瞬間、うち解け合った。モンスターたちの宮廷の代表に対する《好意》+1、さらにモンスターたちは友好的になる。",
  259. ]
  260. ),
  261. "ET" => DiceTable::Table.new(
  262. "感情表",
  263. "1D6",
  264. [
  265. "忠誠",
  266. "友情",
  267. "愛情",
  268. "怒り",
  269. "不信",
  270. "侮蔑",
  271. ]
  272. ),
  273. "FRT" => DiceTable::Table.new(
  274. "お祭り表",
  275. "2D6",
  276. [
  277. "祈願祭。国や重要人物の無病息災を祈ったり、戦いの勝利などを祈る祭り。災害や飢饉、流行り病が起こった付近で行われる。シナリオの目的をクリアしていれば、《民》+(1D6)。",
  278. "血祭り。戦いに向け、士気を向上させる祭り。戦争だけでなく、迷宮探索に向けて行われることも多い。生贄の血を軍神に捧げたりする。このゲームの間、戦闘に勝利すると《民の声》+1、逃走すると《民の声》-1。",
  279. "記念日。建国記念日や領土獲得などの記念日のお祝い。簡単につくることができるが、気がつくと記念日だらけで、何の記念だったかを忘れてしまう。ほどほどに。このセッションの間、行為判定の目で3でも絶対失敗、11でも絶対成功になる(「呪い」の変調を受けているものは、行為判定のサイコロの目が[呪いの数値+1]以下で絶対失敗が発生する。)。",
  280. "星祭。季節のお祭り。冬至や夏至などの祭りや、七夕、お花見、雪祭りなどが含まれる。季節感の少ない迷宮では、殊更にその風情を楽しもうとやたら盛り上がる。宮廷全員、好きなキャラクター1人を選び、そのキャラクターに対する《好意》+1。",
  281. "民衆の宴。民が自発的に開くお祭り、イベント。アキハバラ電気祭りに餃子祭り、コミックマーケットなど、文化や地域の活性化と結びつくものが多い。このセッションの間、好きな施設1つを選んで、その施設の施設レベル+1。",
  282. "誕生日。ランドメイカーや逸材、国の重要人物の誕生日。聖誕祭や花祭りなど、国教の聖人などを祝う国も多い。現王の誕生日を「父の日」、后の誕生日を「母の日」とする国も多い。そのゲームの間、ケーキやおにぎり、缶ジュースなど、1人分が明確な食べ物を食べきったとき、自分のPCが《気力》1点を獲得する。",
  283. "冠婚葬祭。国の重要人物の元服(成人)、婚礼、葬儀、祖先の慰霊などの儀式。格式の高い王国では、もっとも重要な祭礼である。このセッションの間、国力を使った判定の達成値+1。",
  284. "感謝祭。豊漁や豊作などがあったときに自然(迷宮)や精霊、信仰対象など、偉大なるものへの感謝を捧げるお祭り。獲物の毛の一部を切りとって迷宮に感謝する毛祭りや瀬祭り、豊饒を祝う新嘗祭などがある。王国変動表を使用したとき、1回だけ「木」や「革」、「肉」のいずれかを1つ消費すると、その結果を±1の範囲でずらすことができる。",
  285. "鬼祭り。お正月に旧年の悪を正す修正会、豆をまいて福を呼び込む追儺の儀式、怪物に仮装した子供たちが夜の王国をねり歩くハロウィーンなど、悪魔や悪霊を払うお祭り。モンスター除けに行われる。このセッションの間2回だけ、戦闘後に使用する「お宝表」を1段階高いランクのものを使用する。",
  286. "舞踏会。最高の音楽と芸術的な食事、そしてとびきりの衣装で臨む社交界の華。身分や素性を隠してパートナーを探す仮面舞踏会も人気は高い。ちなみに仮面舞踏会では、女性の側から男性をダンスに誘うのが礼儀だぞ。宮廷全員、ランダムにキャラクター1人を選び、そのキャラクターに対する《好意》+1。",
  287. "競技会。国をあげて、スポーツや芸術、ゲームなど、さまざまなジャンルの一番を決めるお祭り、大会。オリンピックや料理勝負、歌合戦などがある。ランダムに能力値1つを選び、宮廷全員は【その能力値/15】の判定を行う。このとき成功した中で、もっとも達成値が高かったキャラクターは、シナリオ終了後、終了フェイズの探索会議で決定されるキャラクターとは別に、勲章を得る。",
  288. ]
  289. ),
  290. "FBT" => DiceTable::Table.new(
  291. "お祭り休憩表",
  292. "2D6",
  293. [
  294. "お祭りに向かう旅人たちとすれ違う。《予算》を3MG獲得する。自国に【宿屋】か【夜店】があればさらに(1D6)MG獲得する。",
  295. "なんでこんなときに、ダンジョンに行かなきゃいけないんだ! 「あ、電報でーす」。このマップの支配者から、お祭りによせて祝辞の電報がやってくる。そうか、オマエのせいかッ!! マップの支配者の名前が分かり、そのキャラクターへの《敵意》+(1D6)。",
  296. "「そういえば、国のみんなが何か言ってたなぁ……」回想シーン。「視察表」を1回使用する。",
  297. "あー、早く帰って、お祭りを楽しみたーい! この時点でキャンプを終了し、すぐに次の部屋に移動すれば、このクォーターは時間の経過が発生しない。",
  298. "どこからか美味しそうな匂いが漂ってくる。「あ、うまそう」死んだふりをしていた民が起き上がる。《配下》を(1D6)人回復する。",
  299. "雰囲気がいつもと違うせいかな。なんかあの人がステキに見える。好きなキャラクターを1人選ぶ。そのキャラクターへの《好意》+1。",
  300. "あ、こんなところにまで屋台が! あてくじ屋さんだ。1MG減らして、好きなアイテムカテゴリを選び、さらにそのカテゴリの中からランダムにアイテム1種を選ぶ。そのアイテムを1個獲得する(レアアイテムは飾ってあるが、絶対当たらない)。",
  301. "お祭りを目指す交易商人と出会う。「あ、王様。これから王国行くんすよ」宮廷の持つ好きな素材を何個でも、同じ数の別の好きな素材と交換してくれる。",
  302. "せっかくお祭りなんだし、肩肘はってないでノリノリでGO!! このゲーム中は食事をするたびに、《民の声》+1。この効果は累積しない。",
  303. "「あ、この歌は……」祭囃子がキミの封印されていたモンスターにまつわる過去の記憶を呼び戻す。好きなモンスター1種類選ぶ。そのモンスターへの《敵意》+1。この感情値は、そのモンスター全般へのものになる。",
  304. "みんなのわくわくがアイテムに乗り移った? ランダムに自分のアイテムスロット1つを選ぶ。そのアイテムのレベルを1点上昇する。",
  305. ]
  306. ),
  307. "WBT" => DiceTable::Table.new(
  308. "全体休憩表",
  309. "2D6",
  310. [
  311. "部屋の中から使えそうな装備をみつくろう。宮廷全員は、それぞれ好きなコモンアイテムのカテゴリを選び、ランダムにコモンアイテムを1個獲得する。そのアイテムにレベルがあれば、それは1レベルのものとなる。",
  312. "みんなで今後の作戦を練る。宮廷全員は、そのターンの間、あらゆる判定の達成値+1。この効果は累積しない。",
  313. "手分けして物資の調達を行う。各キャラクターは、好きな素材を(1D6)個獲得できる。このとき、各キャラクターはアイテム作成を1回行うことができる。",
  314. "体を休めながら他愛もない世間話に花が咲く。宮廷全員は、それぞれ宮廷の中から好きなキャラクター1人を選び、そのキャラクターに対する《好意》+1。",
  315. "宮廷メンバーで交代で見張りを行い、疲労した配下たちを休ませる。《民の声》を[宮廷の人数]点回復する。",
  316. "一行はしっかりと休息を取り、鋭気を養う。宮廷全員の《気力》+2。",
  317. "配下たちと一緒に体を休める。《民の声》+(1D6)。",
  318. "配下たちに見張りを任せ、体を休める。宮廷全員の《HP》を最大値まで回復する。",
  319. "緊急ミーティング! 国家運営に関してみんなで知恵を出し合う。《予算》を[宮廷の人数]MG獲得する。",
  320. "負傷した配下たちの治療を行う。宮廷全員の《配下》が(1D6)人回復する。",
  321. "宮廷の前に光り輝くアイテムが降臨する。レア武具アイテムかレア一般アイテムのどちらかを選ぶ。ランダムにそのアイテムを1種類選び、それを1個獲得する。",
  322. ]
  323. ),
  324. "LBT" => DiceTable::D66Table.new(
  325. "カップル休憩表",
  326. D66SortType::ASC,
  327. {
  328. 11 => "「あーもう、最悪!」仲良く休憩するつもりが、ひどい喧嘩になってしまう。「カップル休憩表」使用者のお互いに対する《敵意》+2。",
  329. 12 => "「何もかもがお前が悪かったのかッ!!」大きな誤解が生まれる。受け身キャラの攻め気キャラ以外に対する《感情値》がすべて0になり、その値の分だけ攻め気キャラに対する《敵意》が上昇する。",
  330. 13 => "「でさぁ、あの人のことなんだけど……」せっかく2人きりなのに、他人の話で盛り上がる。「カップル休憩表」使用者は、宮廷の中から自分たち以外のキャラクター1人を選び、そのキャラクターに対する《好意》+1。",
  331. 14 => "「へぇ、そんなのあるんだ」互いの好きなものについて語り合う。受け身キャラは、攻め気キャラの「好きなもの」1つを選ぶ。受け身キャラは、自分の「好きなもの」1つをそれに変更し、攻め気キャラへの《好意》+1。",
  332. 15 => "「なぁ、オレのことどう思う?」思い切った質問! 受け身キャラは、攻め気キャラに対する《好意》か《敵意》を1点上昇させ、その属性を好きなものに変更できる。",
  333. 16 => "「だいじょうぶ? 無茶するんだから」少し前の失敗について色々と言われてしまう。ありがたいんだけど、少しムカつく。攻め気キャラは受け身キャラに対する《好意》+1、受け身キャラは攻め気キャラに対する《敵意》+1。",
  334. 22 => "「え、もうこんな時間!?」一休みするつもりが、気がつくとかなり時間がたっている。キャンプが終了すると、通常の時間の経過に加え、さらに1クォーターが経過する。「カップル休憩表」使用者のお互いに対する《好意》+1。また、「カップル休憩表」使用者以外のキャラクターは、使用者2人に対する《敵意》+1。",
  335. 23 => "「ねぇねぇ、これわかる?」何気ない質問だが、これは難しい。変な答えはできないぞ。攻め気キャラは[才覚/9]の判定を行う。成功すると、「カップル休憩表」使用者のお互いに対する《好意》+1。失敗すると、何とか危機を切り抜けることができるが、受け身キャラの攻め気キャラに対する《敵意》+1。",
  336. 24 => "「おいおい、まずは落ち着け!」配下同士が喧嘩を始めた。うまく仲裁しないと……。攻め気キャラは、[魅力/9]の判定を行う。成功すると、「カップル休憩表」使用者のお互いに対する《好意》+1。失敗すると、何とか危機を切り抜けることができるが、受け身キャラの攻め気キャラに帯する《敵意》+1。",
  337. 25 => "「オレが解除するからちょっと待ってろ」2人で休憩するつもりが、一緒にトラップにひっかかってしまった。互いの体が密着してしまう。攻め気キャラは、[探索/9]の判定を行う。成功すると、「カップル休憩表」使用者のお互いに対する《好意》+1。失敗すると、何とか危機を切り抜けることができるが、受け身キャラの攻め気キャラに対する《敵意》+1。",
  338. 26 => "「お前は後ろに下がってろ!」休憩中に怪物に襲われる。攻め気キャラは、[武勇/9]の判定を行う。成功すると、「カップル休憩表」使用者のお互いに対する《好意》+1。失敗すると、何とか危機を切り抜けることができるが、受け身キャラの攻め気キャラに対する《敵意》+1。",
  339. 33 => "「なぁ、さっきは悪かったな」誤解が解ける。「カップル休憩表」使用者のお互いに対する《好意》+1。",
  340. 34 => "「これを言ったのはあなただけです。誰にも言わないでくださいね」受け身キャラが隠している夢や秘密を攻め気キャラが知ってしまう。受け身キャラの攻め気キャラに対する《好意》+1。攻め気キャラの受け身キャラに対する《感情値》が《好意》になり、その属性を「忠誠」にする。",
  341. 35 => "「これからも、よろしく頼むぜ。相棒」攻め気キャラが快活に微笑む。受け身キャラの攻め気キャラに対する《好意》+1。攻め気キャラの受け身キャラに対する《感情値》が《好意》になり、その属性を「友情」にする。",
  342. 36 => "「わ、わたしは、あなたのことが……」受け身キャラの思わぬ告白! 受け身キャラの攻め気キャラに対する《好意》+1。攻め気キャラの受け身キャラに対する《感情値》が《好意》になり、その属性を「愛情」にする。",
  343. 44 => "「大丈夫? 痛くないか?」互いに傷を治療しあう。「カップル休憩表」使用者は、お互いの自分に対する《好意》の分だけ、自分の《HP》を回復することができる。どちらかが《HP》を1点以上回復したら、この表の使用者のお互いに対する《好意》+1。",
  344. 45 => "「この冒険が終わったら、伝えたいことが……あるんだ」攻め気キャラの真剣な言葉。え、それって……? 受け身キャラの攻め気キャラに対する《好意》+2。終了フェイズのエピローグ時に攻め気キャラが生きていれば、受け身キャラになにかを伝える。受け身キャラは、それを聞いて《好意》を最大2点まで上昇できる。",
  345. 46 => "「蝕ッ!? ……って、どこ触ってるんですかッ!?」あたりが不意に暗くなり、思わず変なところを触ってしまう。攻め気キャラの受け身キャラに対する《好意》+2、受け身キャラの攻め気キャラに対する《敵意》+2。「カップル休憩表」使用者のどちらか装備・収納している【星の欠片】1個を消費すれば、このイベントを無効化できる。",
  346. 55 => "「これ、はんぶんこしない?」2人仲良く、アイテムを分け合う。「カップル休憩表」使用者が消費アイテムを持っていれば、それを1個使用できる。ただし、その効果の目標は、「カップル休憩表」使用者の2人に変更される。「カップル休憩表」使用者のお互いに対する《好意》+1。",
  347. 56 => "「え? え? えぇぇぇぇッ!?」ふとした拍子に唇がふれあう。受け身キャラの攻め気キャラ以外に対する《好意》がすべて0点になり、その値の分だけ攻め気キャラに対する《好意》を上昇する。",
  348. 66 => "「…………」気がつくとお互い、目をそらせなくなってしまう。そのまま顔を寄せ合い……。「カップル休憩表」使用者のお互いに対する《好意》+2、その属性を「愛情」にする。",
  349. }
  350. ),
  351. "T1T" => DiceTable::Table.new(
  352. "お宝1表",
  353. "1D6",
  354. [
  355. "何もなし",
  356. "何もなし",
  357. "そのモンスターの素材欄の中から、好きな素材1個",
  358. "そのモンスターの素材欄の中から、好きな素材2個",
  359. "そのモンスターの素材欄の中から、好きな素材3個",
  360. "【お弁当】1つを手に入れる",
  361. ]
  362. ),
  363. "T2T" => DiceTable::Table.new(
  364. "お宝2表",
  365. "1D6",
  366. [
  367. "そのモンスターの素材欄の中から、好きな素材3個",
  368. "そのモンスターの素材欄の中から、好きな素材4個",
  369. "そのモンスターの素材欄の中から、好きな素材5個",
  370. "ランダムに回復アイテム1個を選ぶ",
  371. "ランダムに武具アイテム1個を選ぶ。そのアイテムにレベルがあれば、1レベルのものが手に入る",
  372. "ランダムにレア一般アイテム1個を選び、それを手に入れる",
  373. ]
  374. ),
  375. "T3T" => DiceTable::Table.new(
  376. "お宝3表",
  377. "1D6",
  378. [
  379. "そのモンスターの素材欄の中から、好きな素材5個",
  380. "そのモンスターの素材欄の中から、好きな素材7個",
  381. "そのモンスターの素材欄の中から、好きな素材10個",
  382. "好きなコモンアイテムのカテゴリ1種を選び、そのカテゴリからランダムにアイテム1個を選ぶ。そのアイテムにレベルがあれば、アイテムなら1レベルのものが手に入る",
  383. "ランダムにレア一般アイテム1個を選ぶ。そのアイテムにレベルがあれば、1レベルのものが手に入る",
  384. "ランダムにレア武具アイテム1個を選び、それを手に入れる",
  385. ]
  386. ),
  387. "T4T" => DiceTable::Table.new(
  388. "お宝4表",
  389. "1D6",
  390. [
  391. "そのモンスターの素材欄の中から、好きな素材5個",
  392. "そのモンスターの素材欄の中から、好きな素材10個",
  393. "好きなコモンアイテムのカテゴリ1種を選び、そのカテゴリからランダムにアイテム1個を選ぶ。そのアイテムにレベルがあれば、2レベルのものが手に入る",
  394. "好きなコモンアイテムのカテゴリ1種を選び、そのカテゴリからランダムにアイテム1個を選ぶ。そのアイテムにレベルがあれば、3レベルのものが手に入る",
  395. "ランダムにレア一般アイテム1個を選ぶ。そのアイテムにレベルがあれば、2レベルのものが手に入る",
  396. "ランダムにレア武具アイテム1個を選ぶ。そのアイテムにレベルがあれば、1レベルのものが手に入る",
  397. ]
  398. ),
  399. "T5T" => DiceTable::Table.new(
  400. "お宝5表",
  401. "1D6",
  402. [
  403. "そのモンスターの素材欄の中から、好きな素材10個",
  404. "そのモンスターの素材欄の中から、好きな素材15個",
  405. "好きなコモンアイテムのカテゴリ1種を選び、そのカテゴリからランダムにアイテム1個を選ぶ。そのアイテムにレベルがあれば、4レベルのものが手に入る",
  406. "ランダムにレア一般アイテム1個を選ぶ。そのアイテムにレベルがあれば、3レベルのものが手に入る",
  407. "ランダムにレア武具アイテム1個を選ぶ。そのアイテムにレベルがあれば、2レベルのものが手に入る",
  408. "好きなレアアイテム1個を選び、それを入手する",
  409. ]
  410. ),
  411. "ABUS" => DiceTable::Table.new(
  412. "上級肉弾スキル表",
  413. "1D6",
  414. [
  415. "屈強",
  416. "屈強",
  417. "追い討ち",
  418. "追い討ち",
  419. "即席武器",
  420. "即席武器",
  421. ]
  422. ),
  423. "ASHS" => DiceTable::Table.new(
  424. "上級射撃スキル表",
  425. "1D6",
  426. [
  427. "先制射撃",
  428. "先制射撃",
  429. "鷹の目",
  430. "鷹の目",
  431. "ブルズアイ",
  432. "ブルズアイ",
  433. ]
  434. ),
  435. "AASS" => DiceTable::Table.new(
  436. "上級星術スキル表",
  437. "1D6",
  438. [
  439. "星に願いを",
  440. "星に願いを",
  441. "星のこえ",
  442. "星のこえ",
  443. "破裂星",
  444. "破裂星",
  445. ]
  446. ),
  447. "ASUS" => DiceTable::Table.new(
  448. "上級召喚スキル表",
  449. "1D6",
  450. [
  451. "式神",
  452. "式神",
  453. "お引っ越し",
  454. "お引っ越し",
  455. "戦闘召喚",
  456. "戦闘召喚",
  457. ]
  458. ),
  459. "ASCS" => DiceTable::Table.new(
  460. "上級科学スキル表",
  461. "1D6",
  462. [
  463. "蘇生",
  464. "蘇生",
  465. "強化術式",
  466. "強化術式",
  467. "心霊研究",
  468. "心霊研究",
  469. ]
  470. ),
  471. "ALAS" => DiceTable::Table.new(
  472. "上級迷宮スキル表",
  473. "1D6",
  474. [
  475. "迷宮工事",
  476. "迷宮工事",
  477. "迷核解析",
  478. "迷核解析",
  479. "轟宮",
  480. "轟宮",
  481. ]
  482. ),
  483. "ANES" => DiceTable::Table.new(
  484. "上級交渉スキル表",
  485. "1D6",
  486. [
  487. "色気",
  488. "色気",
  489. "威光",
  490. "威光",
  491. "挑発",
  492. "挑発",
  493. ]
  494. ),
  495. "ACOS" => DiceTable::Table.new(
  496. "上級便利スキル表",
  497. "1D6",
  498. [
  499. "心眼",
  500. "心眼",
  501. "隠し味",
  502. "隠し味",
  503. "ながら",
  504. "ながら",
  505. ]
  506. ),
  507. "AENS" => DiceTable::Table.new(
  508. "上級芸能スキル表",
  509. "1D6",
  510. [
  511. "即興詩",
  512. "即興詩",
  513. "国歌",
  514. "国歌",
  515. "隠し芸",
  516. "隠し芸",
  517. ]
  518. ),
  519. "ATOS" => DiceTable::Table.new(
  520. "上級道具スキル表",
  521. "1D6",
  522. [
  523. "中かばん",
  524. "中かばん",
  525. "節約",
  526. "節約",
  527. "相棒",
  528. "相棒",
  529. ]
  530. ),
  531. "RMS" => DiceTable::D66GridTable.new(
  532. "ランダムマップ選択表",
  533. [
  534. ["A-1", "A-1", "A-2", "A-2", "A-3", "A-3"],
  535. ["A-1", "A-1", "A-2", "A-2", "A-3", "A-3"],
  536. ["B-1", "B-1", "B-2", "B-2", "B-3", "B-3"],
  537. ["B-1", "B-1", "B-2", "B-2", "B-3", "B-3"],
  538. ["C-1", "C-1", "C-2", "C-2", "C-3", "C-3"],
  539. ["C-1", "C-1", "C-2", "C-2", "C-3", "C-3"],
  540. ]
  541. ),
  542. "RT" => DiceTable::Table.new(
  543. "視察表",
  544. "2D6",
  545. [
  546. "神託が下る。苦難がPCを襲うが、それは救いのための試練である。このセッションの間、PCが10点以上のダメージをモンスターから受けるたび《民の声》+1。",
  547. "長老が迷宮の昔話をしてくれた。この表を使用したPCが判定で失敗したとき、その判定のサイコロを振り直すことができる。この効果は、このセッションの間に1回だけ使用できる。",
  548. "民は怪物の脅威に怯えている。この表を使用したPCがモンスターの《HP》を0点にすると、《民の声》+2。この効果は、このセッションの間に1回だけ使用できる。",
  549. "日用品が不足しているという不満を持つ民がいるようだ。このセッションの間、自国に「革」を5個輸送するたび《民の声》+1。",
  550. "民たちは王国の守りが薄いのではという不安を抱えていた。このセッションの間、自国に「鉄」を5個輸送するたび《民の声》+1。",
  551. "主婦たちが食糧不足に対する不安を訴えてきた。このセッションの間、自国に「肉」を5個輸送するたび《民の声》+1。",
  552. "民たちは新しい施設の建設を望んでいる。このセッションの間、自国に「木」を5個輸送するたび《民の声》+1。",
  553. "武器の備えが乏しいのではないかという不安があるようだ。このセッションの間、自国に「牙」を5個輸送するたび《民の声》+1。",
  554. "配下にした若者が熱心に未来を語る。この表を使用したPCは《配下》を1人消費して、《特殊配下》を1人増やす。その《特殊配下》に名前をつけ、「生まれ表」でなりたいジョブを決定すること。なりたいジョブに対応した能力値(その《特殊配下》がなりたいジョブの能力値ボーナス欄に書いてある能力値)を使った判定で、このセッションの間に自分が絶対成功すると、その《特殊配下》は、そのジョブの逸材になる。",
  555. "王国は活気に満ちている。この表を使用したPCは《気力》+1、もう一度王国フェイズに行動することができる。",
  556. "民たちはワクワクするような冒険譚を求めている! このセッションのシナリオの目的を達成していたら、終了フェイズの円卓会議の開始時に、(1D6)MGが手に入る。",
  557. ]
  558. ),
  559. "SE" => DiceTable::Table.new(
  560. "特殊遭遇表",
  561. "1D6",
  562. [
  563. "宙を舞う【グレムリン】が、宮廷の方を物欲しそうに眺めている。宮廷の中で、素材欄に「機械」が含まれているアイテムを持っているPC全員は、[才覚/7+装備している素材欄に「機械」が含まれるアイテムの数]の判定を行う。失敗したPCは、そのアイテムをすべて破壊し、[装備している素材欄に「機械」が含まれるアイテムの数]D6点のダメージを受ける。",
  564. "迷宮の壁や床の中に隠れた【群狼】が、キミたちを待ち伏せていた! 【狼牙】にさらされた宮廷全員は、[探索/5+宮廷の人数]の判定を行う。失敗したPCは、自分の《HP》が(1D6)点になる。",
  565. "部屋を埋め尽くすほど大勢の【小鬼】の群れに遭遇する。【小鬼】たちは瞳を赤くし、我を忘れて襲いかかってくる。宮廷全員は[武勇/5+宮廷の人数]の判定を行う。成功したキャラクターは、「牙」の素材を(1D6)個獲得する。失敗したキャラクターは、[(1D6)+宮廷の平均レベル]点のダメージを受ける。",
  566. "【鬼婆】の奴隷商人に出会う。鎖につながれた無数の奴隷が、恨めしそうにこちらを見ている。宮廷の代表は、[魅力/7+宮廷の人数]の判定を行う。成功すれば、【鬼婆】から奴隷を購入することができる。《予算》を1MG消費するたびに、(1D6)人の《民》を獲得できる。その場で自由に宮廷の《配下》として編成すること。判定に失敗すると、【鬼婆】は奴隷を差し向け、襲いかかってくる。宮廷全員は[武勇/9]の判定を行う。失敗したPCは[(1D6)+宮廷の平均レベル]点のダメージを受けた上、《配下》-(1D6)。",
  567. "年若い娘が1人倒れている。宮廷の中で誰か彼女を助ける者がいるなら、(1D6)を振ること。その目が奇数なら、彼女は有能な逸材だった。彼女はお礼を言い、王国に仕えさせてくれという。「生まれ表」でランダムに選んだジョブの逸材になる。偶数なら、彼女は【メデューサ】だった。【石化の視線】が襲いかかる。彼女を助けようとした者は[才覚/7+宮廷の人数]、残りのPCは[才覚/5+宮廷の人数]の判定を行う。失敗した者は、(1D6)点のダメージを受け、「呪い3」の変調を受ける。この判定に宮廷全員が失敗すると宮廷は全滅する。",
  568. "災厄教の巡礼者の一団に出会う。彼らは、迷宮災厄こそおごり高ぶった人類への罰であり、悔い改めよとその教えを説いた。《配下》を1人以上連れているキャラクターは、[魅力/自分の《配下》の数+5]の判定を行う。失敗したPC1人につき、《民の声》-1。",
  569. ]
  570. ),
  571. "IG" => DiceTable::Table.new(
  572. "情報収集表",
  573. "2D6",
  574. [
  575. "調査隊は、伝説の財宝の噂を聞きつける。《配下》を(1D6)人消費すると、迷宮マップの中からランダムに部屋を1つ目標に選ぶことができる。冒険フェイズに目標の捜索に成功すると、ランダムに選んだレアアイテム1個を獲得する。",
  576. "素材のある部屋を見つける。迷宮マップの中からランダムに部屋を1つ目標に選び、好きな素材を1種類選ぶ。冒険フェイズに目標の捜索に成功すると、その素材を[(1D6)+宮廷の平均レベル]個獲得する。",
  577. "噂に聞いたことのある怪物を発見する。迷宮マップの中からランダムに部屋を1つ目標に選ぶ。その部屋に、レベルが[PCの平均レベル+5]以下の好きなモンスターを1体、中立的なモンスターとして配置することができる。",
  578. "調査隊は、怪物にまつわる情報を入手した! 迷宮マップの中から好きな部屋を2つ目標に選ぶ。目標の脅威情報をGMに教えてもらう。",
  579. "危険な迷宮を調査隊は進む。《配下》を1人消費すると、迷宮マップの中から好きな部屋を1つ目標に選ぶことができる。目標の脅威情報と通路情報をGMに教えてもらう。目標から他の部屋に通路がつながっていない場合、PCは行動済みにならず、もう一度、指揮判定を行うことができる。",
  580. "入り口にたどりつく。迷宮マップの中から【入り口】のある部屋1つをGMに教えてもらい、その部屋を目標に選ぶ。目標の脅威情報をGMに教えてもらう。その後、《配下》を消費することができる。《配下》を(1D6)人消費すると、PCは行動済みにならず、もう一度、指揮判定を行うことができる。",
  581. "調査隊は不慮の事故に巻き込まれる。《配下》を1人消費すると、迷宮マップの中から好きな部屋を1つ目標に選ぶことができる。目標の脅威情報と通路情報をGMに教えてもらう。",
  582. "調査隊は無事、迷宮にたどりつく。迷宮マップの中から好きな部屋を1つ目標に選ぶ。目標の脅威情報と通路情報をGMに教えてもらう。",
  583. "難民のいる部屋を発見する。迷宮マップの中からランダムに部屋を1つ目標に選ぶ。冒険フェイズに目標の捜索に成功すると、宮廷の1人は《配下》を(1D6)人獲得する。",
  584. "調査隊は隠し財産がある部屋に接近した! 迷宮マップの中からランダムに部屋を1つ目標に選ぶ。冒険フェイズに目標の捜索に成功すると(1D6)MGを獲得する。",
  585. "調査隊の素晴らしい活躍! 迷宮マップの中から好きな部屋を1つ目標に選ぶ。目標の脅威情報と通路情報をGMに教えてもらう。さらに、「情報収集表」をもう1回使用できる。",
  586. ]
  587. ),
  588. "BDT" => DiceTable::Table.new(
  589. "生まれ決定表",
  590. "1D6",
  591. [
  592. "才覚系生まれ表で決定",
  593. "魅力系生まれ表で決定",
  594. "探索系生まれ表で決定",
  595. "武勇系生まれ表で決定",
  596. "好きな生まれ表で決定",
  597. "好きな生まれ表で決定",
  598. ]
  599. ),
  600. "TBO" => DiceTable::Table.new(
  601. "才覚系生まれ表",
  602. "1D6",
  603. [
  604. "魔導師",
  605. "博士",
  606. "医者",
  607. "宦官",
  608. "商人",
  609. "地図師",
  610. ]
  611. ),
  612. "CBO" => DiceTable::Table.new(
  613. "魅力系生まれ表",
  614. "1D6",
  615. [
  616. "星術師",
  617. "召喚師",
  618. "貴族",
  619. "亭主",
  620. "寿ぎ屋",
  621. "語り部",
  622. ]
  623. ),
  624. "SBO" => DiceTable::Table.new(
  625. "探索系生まれ表",
  626. "1D6",
  627. [
  628. "迷宮職人",
  629. "料理人",
  630. "働き者",
  631. "狩人",
  632. "盗賊",
  633. "鉱工",
  634. ]
  635. ),
  636. "VBO" => DiceTable::Table.new(
  637. "武勇系生まれ表",
  638. "1D6",
  639. [
  640. "武人",
  641. "処刑人",
  642. "衛視",
  643. "冒険者",
  644. "怠け者",
  645. "番人",
  646. ]
  647. ),
  648. "FET" => DiceTable::Table.new(
  649. "好意表",
  650. "1D6",
  651. [
  652. "忠誠",
  653. "忠誠",
  654. "友情",
  655. "友情",
  656. "愛情",
  657. "愛情",
  658. ]
  659. ),
  660. "HET" => DiceTable::Table.new(
  661. "敵意表",
  662. "1D6",
  663. [
  664. "怒り",
  665. "怒り",
  666. "不信",
  667. "不信",
  668. "侮蔑",
  669. "侮蔑",
  670. ]
  671. ),
  672. "IEQ" => DiceTable::Table.new(
  673. "初期装備表",
  674. "2D6",
  675. [
  676. "鉄砲",
  677. "爆弾",
  678. "お守り",
  679. "フルコース",
  680. "星の欠片",
  681. "お弁当",
  682. "ポーション",
  683. "お酒",
  684. "乗騎",
  685. "衣装",
  686. "魔導書",
  687. ]
  688. ),
  689. "SDT" => DiceTable::Table.new(
  690. "スキル決定表",
  691. "1D6",
  692. [
  693. "基本スキル表で決定",
  694. "基本スキル表で決定",
  695. "基本スキル表で決定",
  696. "上級スキル表で決定",
  697. "上級スキル表で決定",
  698. "上級スキル表で決定",
  699. ]
  700. ),
  701. "BUS" => DiceTable::Table.new(
  702. "基本肉弾スキル表",
  703. "1D6",
  704. [
  705. "投げる",
  706. "鉄腕",
  707. "かばう",
  708. "突撃",
  709. "乱舞",
  710. "二刀流",
  711. ]
  712. ),
  713. "SHS" => DiceTable::Table.new(
  714. "基本射撃スキル表",
  715. "1D6",
  716. [
  717. "狙う",
  718. "連射",
  719. "魔弾",
  720. "援護射撃",
  721. "必殺",
  722. "零距離射撃",
  723. ]
  724. ),
  725. "ASS" => DiceTable::Table.new(
  726. "基本星術スキル表",
  727. "1D6",
  728. [
  729. "刻騙し",
  730. "流れ星",
  731. "星占い",
  732. "星剣",
  733. "星界",
  734. "星戦",
  735. ]
  736. ),
  737. "SUS" => DiceTable::Table.new(
  738. "基本召喚スキル表",
  739. "1D6",
  740. [
  741. "宅配便",
  742. "大転移",
  743. "送還",
  744. "転送",
  745. "魔物使い",
  746. "憑依",
  747. ]
  748. ),
  749. "SCS" => DiceTable::Table.new(
  750. "基本科学スキル表",
  751. "1D6",
  752. [
  753. "設計",
  754. "分析",
  755. "マルチタスク",
  756. "錬成",
  757. "抗魔式",
  758. "理力の一撃",
  759. ]
  760. ),
  761. "LAS" => DiceTable::Table.new(
  762. "基本迷宮スキル表",
  763. "1D6",
  764. [
  765. "罠師",
  766. "すりぬけ",
  767. "足止め",
  768. "軽業",
  769. "地裂",
  770. "隠形",
  771. ]
  772. ),
  773. "NES" => DiceTable::Table.new(
  774. "基本交渉スキル表",
  775. "1D6",
  776. [
  777. "スカウト",
  778. "人脈",
  779. "時間稼ぎ",
  780. "命乞い",
  781. "右腕",
  782. "仲間割れ",
  783. ]
  784. ),
  785. "COS" => DiceTable::Table.new(
  786. "基本便利スキル表",
  787. "1D6",
  788. [
  789. "合体攻撃",
  790. "目覚めのキス",
  791. "不屈",
  792. "電撃作戦",
  793. "デート",
  794. "連携攻撃",
  795. ]
  796. ),
  797. "ENS" => DiceTable::Table.new(
  798. "基本芸能スキル表",
  799. "1D6",
  800. [
  801. "宴",
  802. "軍楽",
  803. "武楽",
  804. "呪歌",
  805. "音霊",
  806. "ナルシスト",
  807. ]
  808. ),
  809. "TOS" => DiceTable::Table.new(
  810. "基本道具スキル表",
  811. "1D6",
  812. [
  813. "大かばん",
  814. "お買い物",
  815. "修理",
  816. "プレゼント",
  817. "武器習熟",
  818. "渾身の力",
  819. ]
  820. ),
  821. "EBT" => DiceTable::Table.new(
  822. "空振り休憩表",
  823. "2D6",
  824. [
  825. "「おつとめ、ご苦労様です」同行する民たちが感謝の言葉をかける。《民の声》+1。",
  826. "「おい、サボるな」と仲間から怒られた。いやいや、こっちは今までマジメにやってましたよ。宮廷の中から好きなキャラクター1人を選ぶ。自分のそのキャラクターに対する《敵意》+1。",
  827. "大量大量! 色々な素材が見つかる。肉、牙、鉄、魔素、機械の素材(キャラクターシートの上の段の素材)を1個ずつ獲得する。",
  828. "そこはもう、使い魔が探索してくれていたようだ。サンキュー相棒! この捜索の判定に【使い魔】を利用していれば、行動済みにならず、さらにもう1回行動を行うことができる。",
  829. "危険なトラップを見つけたが、何とか無力化できた。任務完了。自分の《気力》+1。",
  830. "何も見つからなかったか、と思っていたら「いつも、ありがとう」と宮廷の仲間から声をかけられた。まぁ、何もない方がいいか。宮廷の中から好きなキャラクター1人を選ぶ。自分のそのキャラクターに対する《好意》+1",
  831. "「さすが! 素晴らしいお手並みだ」鮮やかな捜索に、仲間の見る目が変わる。宮廷の中から好きなキャラクター1人を選ぶ。そのキャラクターの自分に対する《好意》+1。",
  832. "よしよし、これはいいものが見つかった。好きな1種類の素材を(1D6)個獲得する。この捜索の判定に【使い魔】を使用していれば、獲得数が(1D6)個上昇する。",
  833. "大量大量! 色々な素材が見つかる。衣料、木、火薬、情報、革の素材(キャラクターシートの上の段の素材)を1個ずつ獲得する。",
  834. "うわ! 罠だ。余計なものまで見つけてしまった。宮廷全員は(1D6)点のダメージを受ける。",
  835. "「へぇ、こんなヤツだったのか」仲間の意外な一面を見つける。宮廷の中から好きなキャラクター1人を選ぶ。自分のそのキャラクターに対する《感情値》を反転させ、属性を好きなものに変更できる。",
  836. ]
  837. ),
  838. "ARN" => DiceTable::Table.new(
  839. "人工部屋特殊遭遇表",
  840. "1D6",
  841. [
  842. "他の王国のランドメイカーらしき一行が現れる。彼らは食事が尽きているらしく、アイテムの交換を持ちかけてきた。話を聞くなら、1クォーターが経過し、食事アイテム1個と交換で【ポーション】か【特効薬】1個を獲得できる。話をきかないなら、彼らは食事を無理矢理奪おうとしてくる。宮廷の代表は[魅力/宮廷の人数+5]の判定を行う。失敗すると、食事アイテムを持っているPCは(1D6)点のダメージを受け、持っている食事アイテムをすべて消費する。",
  843. "数人の【人間の屑】が物欲しそうな顔つきでこちらを見ながら、ひそひそと話しあっている。宮廷が、価格が3以上のコモンアイテムを[宮廷の人数の半分]個のアイテムを消費すると、【人間の屑】たちは卑屈な笑みを浮かべながら、この部屋を去っていく。消費しないなら、宮廷全員は[探索/宮廷の人数+5]の判定を行う。失敗した者は、ランダムにアイテムスロット1つを選び、そのスロットに装備・収納されているアイテムをすべて破壊する。",
  844. "ラストエグザイルという修行の旅をしている【ラストサムライ】の一団に出会う。PC1人が素材欄に「鉄」を含むアイテム1個を消費すると、彼らは喜んで旅の噂話を教えてくれる。1クォーターが経過し、宮廷の代表は「情報」の素材を(1D6)個獲得する。各PCは、望むなら食事アイテムを1個ずつ使用できる。アイテムを消費しない場合、彼らは襲いかかってくる。宮廷全員は[武勇/宮廷の人数+5]の判定を行う。失敗した者は、ランダムにアイテムスロット1つを選び、そのスロットに装備・収納されているアイテムをすべて破壊し、(1D6)+1点のダメージを受ける。",
  845. "部屋の片隅に宝箱を見つける。宝箱を開けてみるなら(1D6)を振ること。1なら【宝石】1個を獲得する。2ならランダムに選んだ1レベルのコモンアイテム1個を獲得する。3ならランダムに選んだレア一般アイテムを1個獲得する。4なら【箱入り娘】に魅了されて、ランダムに選んだ自分以外のPC1体に(2D6)点のダメージを与える。5なら【匣男】に抱きつかれ、そのターンの間「散漫1」の変調を受け、《HP》の最大値-3。6なら【生き金貨】がブレスを吐いてきて、宮廷全員は4点のダメージを受ける。",
  846. "宮廷たちの背後から、迷宮の壁に描かれた絵がゆっくりと襲いかかってくる。【逆壁】だ! 宮廷の代表は[才覚/宮廷の人数+7]の判定を行う。成功したら、宮廷は【逆壁】の不意打ちに気づいて、返り討ちにする。失敗したら、宮廷全員は(1D6)点のダメージを受ける。",
  847. "【ウマトカゲ】に乗ったメトロ汗国の斥候たちに出会う。彼らは奴隷を集めに来たようだ。宮廷全員は[武勇/宮廷の人数+5]の判定を行う。失敗した者は《配下》-(1D6)。",
  848. ]
  849. ),
  850. "WEN" => DiceTable::Table.new(
  851. "水域部屋特殊遭遇表",
  852. "1D6",
  853. [
  854. "【エルフ】の集団が現れた。【エルフ】たちは、抜け目なく宮廷の様子をうかがっている。宮廷の代表は、[才覚/13]の判定を行う(「言語」の選択ルールを適用して、深人語を修得していたら自動的に成功する)。成功すると、彼らがPCたちの王国を襲撃しようとしていることが分かる。宮廷全員は[武勇/13-宮廷の人数]の判定を行う。成否にかかわらず、【エルフ】たちの企みは止めることができるが、失敗した者は(1D6)+1点のダメージを受ける。[才覚]の判定に失敗すると彼らの狙いに気づくことができない。終了フェイズの「王国変動」のタイミングで、追加で1回「王国変動表」の4番の効果が発生する。",
  855. "突如現れた【マッハペンギン】に向かって、水中から【鉄砲魚】が砲撃を行う。このままでは、天使と深人の争いに巻き込まれてしまいそうだ。どちらかの加勢をするなら、宮廷全員は[好きな能力値/宮廷の人数+7]の判定を行う。成功したPCが宮廷の人数の半分以上いると、加勢した側が勝利する。天使側に加勢したならPC全員はランダムに回復アイテムを1個ずつ、深人側に加勢したならPC全員はランダムに武具アイテムを1個ずつ獲得する。成功したPCが宮廷の人数の半分未満だと、PC全員は(2D6)点のダメージを受ける。",
  856. "水域の近くから「モウレン、ヤッサ、イナガ貸セエ」という声が近づいてくる。【丹幽霊】だ。宮廷の誰かが【鍋】を1個消費すると、不思議そうな顔をしてそれを持っていき、彼らは水域の向こう側へと消えていく。そうでなければ、宮廷が持っている乗物アイテムがすべて消費される。",
  857. "【河ドワーフ】が水路を伸ばす工事を行っている。このままだと、この部屋は完全に水没してしまうかもしれない。止めたほうがいいのだろうか? 止めるなら、宮廷の代表は[魅力/宮廷の人数+7]の判定を行う。成功すると、快く【河ドワーフ】たちは水路を伸ばす方向を変えてくれる。失敗すると、【河ドワーフ】たちに愉快な罵倒を浴びせられ、宮廷全員の《気力》-1、《民の声》-1。止められないなら、その部屋に【水槽】のトラップが配置される。",
  858. "「ヨーホー! 金目のものをよこしやがれ!」【階賊】の集団に襲われる! 宮廷全員は[武勇/13-宮廷の人数]の判定を行う。失敗した者は、ランダムに自分のアイテムスロット1つを選び、そのスロットに装備・収納されたものをすべて消費し、(1D6)点のダメージを受ける。",
  859. "水の中から突如触手が現れた! 宮廷の1人にからみつくと、水の中に引きずり込んでしまう。宮廷の中からランダムに1人を選ぶ。選ばれたPCは[探索/9+装備・収納している、素材欄に「鉄」が含まれるアイテムの数]の判定を行う。失敗すると、《HP》を([判定の難易度-判定の達成値]D6)点減少する。また、そのPCが装備・収納している、素材欄に「火薬」が含まれるアイテムを破壊する。",
  860. ]
  861. ),
  862. "NEN" => DiceTable::Table.new(
  863. "自然部屋特殊遭遇表",
  864. "1D6",
  865. [
  866. "大きな地響きが聞こえる。この森を構成している大勢の【トレント】たちが別の部屋へと移動しているようだ。ほかの生き物たちも、木々の行進に続いている。森の大移動だ。宮廷の代表は[探索/宮廷の人数+7]の判定を行う。失敗すると、宮廷は【トレント】たちの大行進に出くわしてしまう。宮廷全員は《HP》の現在値を(1D6)点にして、《配下》-(1D6)。",
  867. "天井近くに【アラクネ】の巣を見つける。近くに【蜘蛛の王】の領域があるのかもしれない。駆除しておくべきか……。駆除に挑戦するなら、1クォーターが経過し、PC全員は[武勇/13-宮廷の人数]の判定を行う。判定の成否に関わらず巣を除去することができるが、失敗した者は、アラクネの反撃を受け、(2D6)-2点のダメージを受ける。放っておく場合、終了フェイズの王国変動のタイミングで(1D6)を振る。その出目が、[「周辺階域」欄のそのマップがある土地から自国がある土地までのマス数]以下だった場合、【蜘蛛の王】の襲撃により、自国に残っていた《民》が(5D6)人減少する。",
  868. "やぶの中から突如現れた巨大な怪物を目撃する。【睨み蜥蜴】だ! PC全員は[探索/9]の判定を行う。失敗した者は《HP》を1点にする。",
  869. "【緑の親指】が森の木々を手入れしている。自分が管理する森にやってきたPCたちを警戒しているようだ。宮廷の代表は[才覚/宮廷の人数+7]の判定を行う。成功すると、日常アイテム1個と交換で「木」の素材を(1D6)個獲得できる。失敗した者は(1D6)+6点のダメージを受ける。",
  870. "森の奥から何かを叩くポコポコという音が響いてくる。のぞいてみると、【豆狸】たちが、腹鼓を叩きながら、楽しげに唄っている。PC全員は[魅力/宮廷の人数+5] の判定を行う。成功したPCが宮廷の人数の半分以上いると、楽しい時間を過ごす。各PCは《気力》+1、望むなら食事のアイテムを1個ずつ使用できる。成功した PCが宮廷の人数の半分未満だと、気がつくと辺りには誰もいなくなっている。2クォーターが経過し、各PCは、ランダムにアイテムスロット1つを選び、そのスロットに装備・収納されたものをすべて消費する。",
  871. "その部屋の奥には、茸の森が広がっていた。その中心にたたずむ巨大な【オバケ茸】を【茸人】たちが囲んで、何か祈りを捧げている。……ここなら、もしかすると【百年茸】があるかも。【百年茸】を探すなら、宮廷の中から望む者は[探索/9+この判定に挑戦した回数(初回は1回と数える)]の判定を行う。成功した者は、レア一般アイテムの 【百年茸】を1個獲得する。誰か1人でも失敗すると、【茸人】に見つかり、PC全員は「毒2」の変調を受ける。【百年茸】を探さないなら、安全にその場を離れ、何も起こらない。",
  872. ]
  873. ),
  874. "CEN" => DiceTable::Table.new(
  875. "洞窟部屋特殊遭遇表",
  876. "1D6",
  877. [
  878. "突如、天井から魔法の掘削機械が飛び出してくる。【ドワーフ】の直線主義者の一団だ。このままだと押しつぶされてしまう! PC全員は[探索/宮廷の人数+5]の判定を行う。失敗した者は(1D6)点のダメージを受け、《配下》-(1D6)。その後GMは、その部屋に隣接するシナリオ上、遭遇が設定されていない部屋があれば、そこに向けて通路1本を引く。",
  879. "眠っている【洞窟熊】を見つける。攻撃するか? それとも音を立てないようにやり過ごすか? 攻撃するなら、PC全員は[武勇/7]の判定を行う。判定の成否にかかわらず【洞窟熊】を倒すことはできるが、失敗した者は《HP》を1点にする。やり過ごすなら、PC全員は[探索/宮廷の人数+5]の判定を行う。失敗した者が宮廷の人数の半分以上いると逃げ切れず、PC全員は(1D6)点のダメージを受ける。",
  880. "【まじない師】に率いられた【穴人】に取り囲まれる。【まじない師】は、謎かけをしてくる。宮廷の代表は[才覚/12]の判定を行う。成功すると、彼らはこの部屋を立ち去る。失敗すると【穴人】に襲いかかられ、PC全員は(2D6)点のダメージを受ける。",
  881. "洞窟の奥から【大蝙蝠】の群れが飛んでくる。PC全員は[探索/宮廷の人数+7]の判定を行う。失敗した者は「毒3」の変調を受ける。",
  882. "【ドラゴン】が現れた! 流暢な「ひとつの言葉」を使って、その巨大な生き物は「うるさくて眠れない」と苦情を言ってきた。宮廷の代表は[魅力/宮廷の人数+7]の判定を行う。成功すると丁重にお帰りいただくことができる。失敗すると、宮廷全員は15点のダメージを受ける。",
  883. "空気がじめじめとしてくる。【黴姫】の領域が近いようだ。下手をすると食事を駄目にしてしまうかもしれない。PC全員は[才覚/宮廷の人数+5]の判定を行う。失敗した者は自分の装備・収納している食事アイテムをすべて破壊する。",
  884. ]
  885. ),
  886. "SEN" => DiceTable::Table.new(
  887. "天空部屋特殊遭遇表",
  888. "1D6",
  889. [
  890. "【取立人】が現れ、慇懃に挨拶すると、PCたちの栄光を褒め称える。そして、その栄光は天使の導きによるものだから、と対価を要求してくる。対価を支払うなら《予算》を[PCたちの平均レベル]MG消費するか、王国に残った《民》を[PCたちの平均レベル]人消費する。いずれかを消費すると【取立人】は満足そうにうなずき、未来に起こる出来事をこっそり耳打ちする。宮廷は、そのセッション中、振ったサイコロを1度だけ振り直すことができるようになる。対価をはねのけると、PC全員は「呪い3」の変調を受ける。",
  891. "【羽根兜の乙女】が立ち塞がり、「勇者よ! きさまの魂をもらい受ける!」と決闘を挑んでくる。決闘を受けるなら、宮廷の代表は[武勇/14]の判定を行う。成功すると、【羽根兜の乙女】は、「次は絶対勝つ!」と、泣きながら逃げていく。判定に成功したPCが装備可能なら【愛】を1個獲得する。失敗した者は(1D6)+8点のダメージを受け、【羽根兜の乙女】から「腰抜けが。とんだ見込み違いだ」と罵倒される。決闘を拒否するなら、【羽根兜の乙女】の怒りを買い、PC全員は(2D6)点のダメージを受ける。",
  892. "一天にわかにかき曇る。【雲神】だ! (1D6)を振る。1なら雨が振ってきて、PC全員は素材欄に「火薬」が含まれるアイテムを破壊する。2なら雷が落ちてきて、素材欄に「鉄」が含まれるアイテムを装備・収納しているPCは(3D6)点のダメージを受ける。3なら霧がたちこめ、PC全員は、その部屋で行う判定の達成値が2点減少する。4なら突風が吹き、PC全員は《配下》を[(1D6)×1/2]人減少する。5か6なら心地良い風が吹き、PC全員は《気力》+2。",
  893. "腹を空かせた【鷲獅子】が、空中から襲いかかる! PC全員は[武勇/宮廷の人数+7]の判定を行う。【乗騎】を装備・収納しているPCは難易度が2点上昇する。判定に失敗した者は(2D6)点のダメージを受ける。【乗騎】を装備・収納しているPCが判定に失敗した場合、その【乗騎】がすべて消費される。",
  894. "空に巨大な星が輝く。その星が不気味に笑った気がする。あれは【星首】だ。宮廷の中から、ランダムに2人のPCを選ぶ。そのPCが装備・収納している【星の欠片】をすべて破壊する。",
  895. "何か雪のようなものが降ってきたと思ったら、気分が悪くなってきた。上空を見あげると、【蝶の王】が羽ばたいている。狂気の鱗粉だ! PC全員は[魅力/9]の判定を行う。失敗した者は、「毒6」と「散漫1」と「憤怒」の変調を受ける。",
  896. ]
  897. ),
  898. "OEN" => DiceTable::Table.new(
  899. "異界部屋特殊遭遇表",
  900. "1D6",
  901. [
  902. "扉をあけて、ハグルマ風の衣装を着た人物が現れる。何やら話が通じない。もしかすると噂に名高い【稀人】というやつか? 《配下》たちが何かを期待しているのを感じる。宮廷の代表は[才覚/宮廷の人数+7]の判定を行う。成功すると、意思の疎通に成功する。【稀人】1体を《特殊配下》にできる。王国につれて帰ることができると《モンスターの民》になる。失敗すると、【稀人】は話が通じず途方にくれ、扉の向こうに帰っていく。《民の声》-1。",
  903. "【ケチャップリンス】と【メイクイーン】が激論を交わしている。どうやら、どちらが【マヨネーズキング】にふさわしいかについて語り合っているようだ。仲裁するなら、宮廷の代表は[才覚/宮廷の人数+7の判定を行う。成功すると美味しい食べ物を御馳走してくれる。PC全員は《HP》を(1D6)点回復し、《気力》+1。失敗するとPC全員は「肥満2」の変調を受ける。スルーするなら、PC全員は[探索/7]の判定を行う。誰か1人でも失敗するとPC全員は「肥満2」の変調を受ける。",
  904. "突然、その部屋が闇に包まれ、重力がなくなる。扉が開く音がして、そこから強い光がさしこんできた。【灰色の宇宙人】だ。【乗騎】、【使い魔】、【家畜】のいずれかを装備・収納しているPCは[魅力/宮廷の人数+7]の判定を行う。成功した者は【乗騎】、【使い魔】、【家畜】のうちいずれか1個と交換で【星の欠片】か【携帯電話】1個を獲得できる。判定に失敗した者は【乗騎】、【使い魔】、【家畜】のうちいずれか1個を消費する。",
  905. "扉を破って、無数の「死にぞこないの群れが現れた。ゾンビラッシュ! PC全員は[武勇/宮廷の人数+7]の判定を行う。失敗した者は、(1D6)点のダメージと「毒3」の変調を受ける。",
  906. "遠くの方から何かが転がってくる。ゴロゴロと音が大きくなり、気がつくと【悪意の骰子】が眼前に迫っていた! 宮廷全員は[探索/9]の判定を行う。失敗した者は「呪い4」の変調を受け、奇妙な姿に変えられる。",
  907. "暗闇の中に幾つかの星が輝く。あれは【星座獣】だ! PC全員は[魅力/9]の判定を行う。失敗した者は[そのPCが装備・収納している【星の欠片】の合計数+1]D6点のダメージを受ける。",
  908. ]
  909. ),
  910. }.merge(ITEM_TABLES).freeze
  911. end
  912. end
  913. end

lib/bcdice/game_system/meikyu_kingdom_basic/word_table.rb

100.0% lines covered

100.0% branches covered

15 relevant lines. 15 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class MeikyuKingdomBasic
  5. # 単語表1(D66)
  6. # override
  7. 1 def mk_word_1_table(num)
  8. table = [
  9. 1 [11, "魔法"],
  10. [12, "おめかし"],
  11. [13, "狭いところ"],
  12. [14, "夜更かし"],
  13. [15, "節約"],
  14. [16, "会議"],
  15. [22, "ヒゲ"],
  16. [23, "孤独"],
  17. [24, "説教"],
  18. [25, "自分探し"],
  19. [26, "異性"],
  20. [33, "ヒラヒラした服"],
  21. [34, "平穏な生活"],
  22. [35, "自分語り"],
  23. [36, "風呂"],
  24. [44, "古いもの"],
  25. [45, "頭が悪い人"],
  26. [46, "暗闇"],
  27. [55, "許嫁"],
  28. [56, "民"],
  29. [66, "バカ"],
  30. ]
  31. 1 return get_table_by_number(num, table)
  32. end
  33. # 単語表2(D66)
  34. # override
  35. 1 def mk_word_2_table(num)
  36. table = [
  37. 1 [11, "科学"],
  38. [12, "読書"],
  39. [13, "広いところ"],
  40. [14, "早起き"],
  41. [15, "ムダ"],
  42. [16, "仕事"],
  43. [22, "陰謀"],
  44. [23, "みんなで集まること"],
  45. [24, "ナンパ"],
  46. [25, "昔話"],
  47. [26, "同性"],
  48. [33, "武器の手入れ"],
  49. [34, "戦争"],
  50. [35, "人の噂"],
  51. [36, "散髪"],
  52. [44, "新しいもの"],
  53. [45, "頭がよい人"],
  54. [46, "光"],
  55. [55, "親"],
  56. [56, "外国人"],
  57. [66, "ホラ話"],
  58. ]
  59. 1 return get_table_by_number(num, table)
  60. end
  61. # 単語表3(D66)
  62. # override
  63. 1 def mk_word_3_table(num)
  64. table = [
  65. 1 [11, "子供"],
  66. [12, "弱い人"],
  67. [13, "処刑"],
  68. [14, "叙事詩"],
  69. [15, "煙草"],
  70. [16, "病院"],
  71. [22, "演説"],
  72. [23, "酒盛り"],
  73. [24, "料理"],
  74. [25, "武芸"],
  75. [26, "田舎"],
  76. [33, "自分の国"],
  77. [34, "伝統"],
  78. [35, "お祭り"],
  79. [36, "告げ口"],
  80. [44, "自分の声"],
  81. [45, "マヨネーズ"],
  82. [46, "おせっかい"],
  83. [55, "猫"],
  84. [56, "混沌"],
  85. [66, "占い"],
  86. ]
  87. 1 return get_table_by_number(num, table)
  88. end
  89. # 単語表4(D66)
  90. # override
  91. 1 def mk_word_4_table(num)
  92. table = [
  93. 1 [11, "年寄り"],
  94. [12, "強い人"],
  95. [13, "空想"],
  96. [14, "冗談"],
  97. [15, "クスリ"],
  98. [16, "怪物"],
  99. [22, "一騎打ち"],
  100. [23, "賭け事"],
  101. [24, "歌"],
  102. [25, "勉強"],
  103. [26, "都会"],
  104. [33, "冒険"],
  105. [34, "ダイナマイト大帝"],
  106. [35, "盗み"],
  107. [36, "言い訳"],
  108. [44, "隣のキャラのジョブ"],
  109. [45, "小鬼"],
  110. [46, "謝ること"],
  111. [55, "隣のキャラのクラス"],
  112. [56, "星"],
  113. [66, "肉"],
  114. ]
  115. 1 return get_table_by_number(num, table)
  116. end
  117. end
  118. end
  119. end

lib/bcdice/game_system/one_way_heroics/dungeon_table.rb

95.24% lines covered

75.0% branches covered

21 relevant lines. 20 lines covered and 1 lines missed.
4 total branches, 3 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class OneWayHeroics < Base
  5. 1 class DungeonTable
  6. 1 attr_reader :key
  7. 1 def initialize(name, key, type, items)
  8. 2 @name = name
  9. 2 @key = key
  10. 2 @items = items.freeze
  11. 2 m = /(\d+)D(\d+)/i.match(type)
  12. 2 else: 2 then: 0 unless m
  13. raise ArgumentError, "Unexpected table type: #{type}"
  14. end
  15. 2 @times = m[1].to_i
  16. 2 @sides = m[2].to_i
  17. end
  18. 1 def roll_with_day(day, randomizer)
  19. 9 value = randomizer.roll_sum(@times, @sides)
  20. 9 then: 4 else: 5 value += @times if day >= 4
  21. 9 index = value - @times
  22. 9 return "#{@name}(#{value}) > #{@items[index]}"
  23. end
  24. end
  25. 1 DUNGEON_TABLE = DungeonTable.new(
  26. "ダンジョン表",
  27. "DNGN",
  28. "1D6",
  29. [
  30. "犬小屋(155ページ)",
  31. "犬小屋(155ページ)",
  32. "「ダンジョン遭遇表」(153ページ)へ移動。小型ダンジョンだ。",
  33. "「ダンジョン遭遇表」(153ページ)へ移動。小型ダンジョンだ。",
  34. "「ダンジョン遭遇表」(153ページ)へ移動。ここは中型ダンジョンなので、モンスターが出現した場合、数が1体増加する。さらにイベントの経験値が1増加する。",
  35. "「ダンジョン遭遇表」(153ページ)へ移動。ここは大型ダンジョンなので、モンスターが出現した場合、数が2体増加する。さらにイベントの経験値が2増加する。",
  36. "牢獄遭遇表へ移動(154ページ)。牢獄つきダンジョン。",
  37. ]
  38. )
  39. 1 DUNGEON_TABLE_PLUS = DungeonTable.new(
  40. "ダンジョン表プラス",
  41. "DNGNP",
  42. "2D6",
  43. [
  44. "犬小屋(基本155ページ)",
  45. "犬小屋(基本155ページ)",
  46. "犬小屋(基本155ページ)",
  47. "犬小屋(基本155ページ)",
  48. "「ダンジョン遭遇表」(基本153ページ)へ移動。小型ダンジョンだ。",
  49. "「ダンジョン遭遇表」(基本153ページ)へ移動。小型ダンジョンだ。",
  50. "「ダンジョン遭遇表」(基本153ページ)へ移動。ここは中型ダンジョンのため、モンスターが出現した場合、数が1体増加する。またイベントの【経験値】が1増加する。",
  51. "「ダンジョン遭遇表」(基本153ページ)へ移動。ここは大型ダンジョンのため、モンスターが出現した場合、数が2体増加する。またイベントの【経験値】が2増加する。",
  52. "「ダンジョン遭遇表」(基本153ページ)へ移動。近くに寄っただけで吸い込まれる罠のダンジョンだ。「ダンジョン遭遇表」を使用したあと、中央にあるモニュメントに触れて転移して出るか、【鉄格子】と戦闘して出るか選択する。転移した場合は闇の目の前に出てしまい、全力ダッシュで【ST】を1D6消費する。【鉄格子】との戦闘では逃走を選択できない。",
  53. "「ダンジョン遭遇表」(基本153ページ)へ移動。水浸しのダンジョンで、「ダンジョン遭遇表」を使用した直後に【ST】が3減少する。「水泳」",
  54. "水路に囲まれた水上遺跡だ。なかに入るなら【ST】を4消費(「水泳」)してから「ダンジョン遭遇表」(基本153ページ)へ移動。イベントの判定に成功すると追加で【豪華な宝箱】が1つ出現し、戦闘か開錠を試みられる。",
  55. "「牢獄遭遇表」(基本154ページ)へ移動。牢獄つきダンジョンだ。",
  56. "砂の遺跡にたどりつき、「牢獄遭遇表」(基本154ページ)へ移動。モンスターが出現した場合、数が2体増加する。またイベントの【経験値】が2増加する。イベントの判定に成功すると追加で【珍しい箱】が1つ出現し、戦闘か開錠を試みられる。",
  57. ]
  58. )
  59. end
  60. end
  61. end

lib/bcdice/game_system/one_way_heroics/random_event_table.rb

87.3% lines covered

66.67% branches covered

63 relevant lines. 55 lines covered and 8 lines missed.
18 total branches, 12 branches covered and 6 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class OneWayHeroics < Base
  5. 1 class RandomEventTable
  6. 1 def initialize(name, type, items)
  7. 2 @name = name
  8. 2 @items = items.freeze
  9. 2 m = /(\d+)D(\d+)/i.match(type)
  10. 2 else: 2 then: 0 unless m
  11. raise ArgumentError, "Unexpected table type: #{type}"
  12. end
  13. 2 @times = m[1].to_i
  14. 2 @sides = m[2].to_i
  15. end
  16. 1 def roll_with_day(day, randomizer)
  17. 19 value = randomizer.roll_sum(@times, @sides)
  18. 19 index = value - 1
  19. 19 chosen = @items[index]
  20. chosen =
  21. 19 then: 5 if chosen.respond_to?(:roll)
  22. 5 else: 14 chosen.roll(randomizer)
  23. 14 then: 14 elsif chosen.respond_to?(:roll_with_day)
  24. 14 chosen.roll_with_day(day, randomizer)
  25. else: 0 else
  26. chosen
  27. end
  28. 19 return "#{@name}(#{value}) > #{chosen}"
  29. end
  30. end
  31. 1 class BranchByDay
  32. 1 def initialize(text, less_than_equal, greater)
  33. 6 @text = text
  34. 6 @greater = greater
  35. 6 @less_than_equal = less_than_equal
  36. end
  37. 1 def roll_with_day(day, randomizer)
  38. 7 value = randomizer.roll_once(6)
  39. 7 chosen = choice(value, day)
  40. chosen =
  41. 7 then: 1 if chosen.respond_to?(:roll_with_day)
  42. 1 else: 6 "#{chosen.key}#{day} > #{chosen.roll_with_day(day, randomizer)}"
  43. 6 then: 5 elsif chosen.ascii_only?
  44. 5 [chosen, TABLES[chosen].roll(randomizer)].join(" > ")
  45. else: 1 else
  46. 1 chosen
  47. end
  48. result = <<~RESULT.chomp
  49. 7 #{@text} >
  50. 1D6 > #{value} > #{branch_result(value, day)} >
  51. #{chosen}
  52. RESULT
  53. 7 return result
  54. end
  55. 1 def choice(value, day)
  56. raise NotImplementedError
  57. end
  58. 1 def branch_result(value, day)
  59. raise NotImplementedError
  60. end
  61. end
  62. 1 class BranchByElapsedDays < BranchByDay
  63. 1 def choice(value, day)
  64. 7 then: 3 else: 4 value > day ? @greater : @less_than_equal
  65. end
  66. 1 def branch_result(value, day)
  67. 7 then: 3 if value > day
  68. 3 "日数[#{day}]を超えている"
  69. else: 4 else
  70. 4 "日数[#{day}]以下"
  71. end
  72. end
  73. end
  74. 1 class BranchByDayParity < BranchByDay
  75. 1 def choice(value, _)
  76. then: 0 else: 0 value.odd? ? @greater : @less_than_equal
  77. end
  78. 1 def branch_result(value, _)
  79. then: 0 if value.odd?
  80. "奇数"
  81. else: 0 else
  82. "偶数"
  83. end
  84. end
  85. end
  86. 1 class MoveToTableWithDay
  87. 1 def initialize(text, table)
  88. 2 @text = text
  89. 2 @table = table
  90. end
  91. 1 def roll_with_day(day, randomizer)
  92. <<~RESULT.chomp
  93. 7 #{@text} >
  94. #{@table.key}#{day} > #{@table.roll_with_day(day, randomizer)}
  95. RESULT
  96. end
  97. end
  98. 1 RANDOM_EVENT_TABLE = RandomEventTable.new(
  99. "ランダムイベント表",
  100. "1D6",
  101. [
  102. BranchByElapsedDays.new(
  103. "さらに1D6を振る。現在PCがいるエリアの【日数】以下なら「施設表」へ移動。【日数】を超えていれば「ダンジョン表」(153ページ)へ移動。",
  104. "FCLT",
  105. DUNGEON_TABLE
  106. ),
  107. BranchByElapsedDays.new(
  108. "さらに1D6を振る。現在PCがいるエリアの【日数】以下なら「世界の旅表」(157ページ)へ移動。【日数】を超えていれば「野外遭遇表(OUTENC)」(155ページ)へ移動。",
  109. "「世界の旅表」(157ページ)へ。",
  110. "OUTENC"
  111. ),
  112. MoveToTable.new("「施設表」へ移動。", "FCLT"),
  113. "「世界の旅表」(157ページ)へ移動。",
  114. MoveToTable.new("「野外遭遇表」(155ページ)へ移動。", "OUTENC"),
  115. MoveToTableWithDay.new("「ダンジョン表」(152ページ)へ移動。", DUNGEON_TABLE),
  116. ]
  117. )
  118. 1 RANDOM_EVENT_TABLE_PLUS = RandomEventTable.new(
  119. "ランダムイベント表プラス",
  120. "1D6",
  121. [
  122. BranchByElapsedDays.new(
  123. "さらに1D6を振る。現在PCがいるエリアの【日数】以下なら施設表プラス(022ページ)へ移動。【経過日数】を超えていればダンジョン表プラス(025ページ)へ移動",
  124. "FCLTP",
  125. DUNGEON_TABLE_PLUS
  126. ),
  127. BranchByElapsedDays.new(
  128. "さらに1D6を振る。現在PCがいるエリアの【日数】以下なら世界の旅表(基本157ページ)へ移動。【経過日数】を超えていれば野外遭遇表(基本155ページ)へ移動",
  129. "「世界の旅表」(157ページ)へ。",
  130. "OUTENC"
  131. ),
  132. BranchByElapsedDays.new(
  133. "さらに1D6を振る。現在PCがいるエリアの【日数】以下なら世界の旅表2(028ページ)へ移動。【経過日数】を超えていれば野外遭遇表プラス(025ページ)へ移動",
  134. "世界の旅表2(028ページ)へ。",
  135. "OUTENCP"
  136. ),
  137. BranchByDayParity.new(
  138. "さらに1D6を振る。奇数なら世界の旅表(基本157ページ)へ移動。偶数なら世界の旅表2(028ページ)へ移動",
  139. "世界の旅表(基本157ページ)へ。",
  140. "世界の旅表2(028ページ)へ。"
  141. ),
  142. MoveToTable.new("施設表プラスへ移動(022ページ)", "FCLTP"),
  143. MoveToTableWithDay.new("ダンジョン表プラスへ移動(025ページ)", DUNGEON_TABLE_PLUS)
  144. ]
  145. )
  146. end
  147. end
  148. end

lib/bcdice/game_system/one_way_heroics/tables.rb

100.0% lines covered

100.0% branches covered

29 relevant lines. 29 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class OneWayHeroics < Base
  5. 1 class GoldFlow
  6. 1 def initialize(times, action)
  7. 3 @times = times
  8. 3 @action = action
  9. end
  10. 1 def roll(randomizer)
  11. 3 dice_list = randomizer.roll_barabara(@times, 6)
  12. 3 dice_total = dice_list.sum()
  13. 3 gold = dice_total * 100
  14. sequence = [
  15. 3 "#{@times}D6に100を掛け、それだけの【所持金】を#{@action}",
  16. "#{@times}D6[#{dice_list.join(',')}]*100",
  17. "【所持金】#{gold} を#{@action}"
  18. ]
  19. 3 return sequence.join(" > ")
  20. end
  21. end
  22. 1 class StatusDown
  23. 1 def initialize(status, times)
  24. 3 @status = status
  25. 3 @times = times
  26. end
  27. 1 def roll(randomizer)
  28. 3 dice_list = randomizer.roll_barabara(@times, 6)
  29. 3 total = dice_list.sum()
  30. sequence = [
  31. 3 "#{@status}が#{@times}D6減少する",
  32. "#{@times}D6[#{dice_list.join(',')}]",
  33. "#{@status}が #{total} 減少する"
  34. ]
  35. 3 return sequence.join(" > ")
  36. end
  37. end
  38. 1 class MoveToTable
  39. 1 def initialize(text, table_key)
  40. 34 @text = text
  41. 34 @table_key = table_key
  42. end
  43. 1 def roll(randomizer)
  44. <<~RESULT.chomp
  45. 27 #{@text} >
  46. #{@table_key} > #{TABLES[@table_key].roll(randomizer)}
  47. RESULT
  48. end
  49. end
  50. TABLES = {
  51. 1 "FT" => DiceTable::ChainTable.new(
  52. "ファンブル表",
  53. "1D6",
  54. [
  55. "装備以外のアイテムのうちプレイヤー指定の1つを失う",
  56. "装備のうちプレイヤー指定の1つを失う",
  57. GoldFlow.new(1, "失う"), # "1D6に100を掛け、それだけの【所持金】を失う",
  58. GoldFlow.new(1, "拾う"), # "1D6に100を掛け、それだけの【所持金】を拾う",
  59. "【経験値】2を獲得する",
  60. "【経験値】4を獲得する",
  61. ]
  62. ),
  63. "DC" => DiceTable::ChainTable.new(
  64. "魔王追撃表",
  65. "1D6",
  66. [
  67. "装備以外のアイテムのうちGM指定の1つを失う",
  68. "装備のうちGM指定の1つを失う",
  69. GoldFlow.new(2, "失う"), # "2D6に100を掛け、それだけの【所持金】を失う",
  70. StatusDown.new("【LIFE】", 1), # 【LIFE】が1D6減少する
  71. StatusDown.new("【ST】", 1), # 【ST】が1D6減少する
  72. StatusDown.new("【LIFE】", 2) # 【LIFE】が2D6減少する
  73. ]
  74. ),
  75. "PR" => DiceTable::Table.new(
  76. "進行ルート表",
  77. "1D6",
  78. [
  79. "少し荒れた地形が続く。【日数】から【筋力】を引いただけ【ST】が減少する(最低0)",
  80. "穏やかな地形が続く。【日数】から【敏捷】を引いただけ【ST】が減少する(最低0)",
  81. "険しい岩山だ。【日数】に1を足して【生命】を引いただけ【ST】が減少する(最低0)「登山」",
  82. "山で迷った。【日数】に2を足して【知力】を引いただけ【ST】が減少する(最低0)「登山」",
  83. "川を泳ぐ。【日数】に1を足して【意志】を引いただけ【ST】が減少する(最低0)「水泳」",
  84. "広い川を船で渡る。【日数】に2を足して【魅力】を引いただけ【ST】が減少する(最低0)「水泳」"
  85. ]
  86. ),
  87. "TT" => DiceTable::Table.new(
  88. "会話テーマ表",
  89. "1D6",
  90. [
  91. "身体の悩みごとについて話す。【筋力】で判定。",
  92. "仕事の悩みごとについて話す。【敏捷】で判定。",
  93. "家族の悩みごとについて話す。【生命】で判定。",
  94. "勇者としてこれでいいのか的悩みごとを話す。【知力】で判定。",
  95. "友人関係の悩みごとを話す。【意志】で判定。",
  96. "恋の悩みごとを話す。【魅力】で判定。"
  97. ]
  98. ),
  99. "EC" => DiceTable::Table.new(
  100. "逃走判定表",
  101. "1D6",
  102. [
  103. "崖を登れば逃げられそうだ。【筋力】を使用する。",
  104. "障害物はない。走るしかない。【敏捷】を使用する。",
  105. "しつこく追われる。【生命】を使用する。",
  106. "隠れられる地形がある。【知力】を使用する。",
  107. "背中を向ける勇気が出るか? 【意志】を使用す",
  108. "もう人徳しか頼れない。【魅力】を使用する。"
  109. ]
  110. ),
  111. "RNPC" => DiceTable::Table.new(
  112. "ランダムNPC特徴表",
  113. "2D6",
  114. [
  115. "【物持ちの】",
  116. "【目のいい】",
  117. "【弱そうな】",
  118. "【宝石好きな】",
  119. "【エッチな】",
  120. "【ケチな】",
  121. "【変態の】",
  122. "【金持ちの】",
  123. "【強そうな】",
  124. "【目の悪い】",
  125. "【すばやい】"
  126. ]
  127. ),
  128. "SCT" => DiceTable::Table.new(
  129. "偵察表",
  130. "1D6",
  131. [
  132. "山に突き当たる。「登山」判定:【筋力】 ジャッジ:山を登る描写。",
  133. "川を流れ下る。「水泳」判定:【敏捷】 ジャッジ:川でピンチに陥る描写。",
  134. "広い湖だ……。「水泳」判定:【生命】 ジャッジ:湖面を泳ぐ描写。",
  135. "山の楽なルートを探そう。「登山」判定:【知力】 ジャッジ:山の豆知識。",
  136. "迫る闇から恐怖のあまり目を離せない。判定:【意志】 ジャッジ:勇者としての決意。",
  137. "任意のNPCに会って情報を聞く。判定:【魅力】 ジャッジ:相手を立てる会話。"
  138. ]
  139. ),
  140. "FCLT" => DiceTable::Table.new(
  141. "施設表",
  142. "2D6",
  143. [
  144. "聖なる神殿(152ページ)。",
  145. "魔王の力を封じた神殿(152ページ)。",
  146. "耳長たちの村(152ページ)。",
  147. "「村遭遇表」へ移動。大きな街なので村遭遇表を2回使用し、好きな結果を選べる。",
  148. "「村遭遇表」へ移動。小さな村だ。",
  149. "エリアの地形が「雪原」なら雪国の小屋(152ページ)。エリアの地形が「山岳」なら山小屋(152ページ)。それ以外の地形なら「村遭遇表」へ移動。この村は「石の小屋」だ。",
  150. "村遭遇表」へ移動。小さな村だ。",
  151. "村遭遇表」へ移動。大きな街なので村遭遇表を2回使用し、好きな結果を選べる。",
  152. "滅びた石の小屋(152ページ)。",
  153. "滅びた小さな村(152ページ)。",
  154. "闇ギルド(152ページ)。"
  155. ]
  156. ),
  157. "FCLTP" => DiceTable::D66Table.new(
  158. "施設表プラス",
  159. D66SortType::ASC,
  160. {
  161. 11 => "聖なる神殿(基本152ページ)",
  162. 12 => "魔王の力を封じた神殿(基本152ページ)",
  163. 13 => "耳長たちの村(基本152ページ)判定成功時に【耳長の軽い弓】【耳長の杖】を購入可能",
  164. 14 => "村遭遇表へ移動(基本151ページ)大きな街なので村遭遇表を2回振り、好きな結果を選べる",
  165. 15 => "村遭遇表へ移動(基本151ページ)小さな村",
  166. 16 => "エリアの地形が雪原なら雪国の小屋(基本152ページ)エリアの地形が山岳なら山小屋(基本152ページ)それ以外の地形なら石の小屋、村遭遇表へ移動(基本151ページ)",
  167. 22 => "村遭遇表へ移動(基本151ページ)小さな村",
  168. 23 => "村遭遇表へ移動(基本151ページ)大きな街なので村遭遇表を2回振り、好きな結果を選べる",
  169. 24 => "滅びた石の小屋(基本152ページ)",
  170. 25 => "滅びた小さな村(基本152ページ)",
  171. 26 => "闇ギルド(基本152ページ)判定成功時に一度だけ【闇ギルド袋屋】に3000シルバ支払い【所持重量】を1増加することができる。",
  172. 33 => "小さな店遭遇表プラスへ移動(023ページ)",
  173. 34 => "酒場遭遇表プラスへ移動",
  174. 35 => "酒場遭遇表プラスへ移動",
  175. 36 => "錬金おばばの家(024ページ)",
  176. 44 => "鍛冶屋の家(024ページ)",
  177. 45 => "半獣人の隠れ家(024ページ)",
  178. 46 => "罪人の街(024ページ)",
  179. 55 => "封印の街(024ページ)",
  180. 56 => "水上の街(024ページ)",
  181. 66 => "人魚の集落(024ページ)",
  182. }
  183. ),
  184. "OUTENC" => DiceTable::ChainTable.new(
  185. "野外遭遇表",
  186. "1D6",
  187. [
  188. MoveToTable.new("エリアの地形ごとの野外モンスター表へ移動。モンスターのうち1体にランダムな特徴がつく。モンスター特徴表(156ページ)を使用する。", "MONFT"),
  189. "エリアの地形ごとの野外モンスター表へ移動",
  190. "エリアの地形ごとの野外モンスター表へ移動",
  191. "アンデッドの群れ(156ページ)",
  192. "盗賊の群れ(156ページ)",
  193. MoveToTable.new("希少動物表(基本156ページ)へ移動", "RANI"),
  194. ]
  195. ),
  196. "OUTENCP" => DiceTable::ChainTable.new(
  197. "野外遭遇表プラス",
  198. "1D6",
  199. [
  200. MoveToTable.new("エリアの地形ごとの野外モンスター表プラスへ移動。モンスターのうち1体にランダムな特徴がつく。モンスター特徴表プラス(027ページ)を使用する。", "MONFTP"),
  201. "エリアの地形ごとの野外モンスター表プラスへ移動し、出現したモンスターとの戦闘が発生する",
  202. "スライムモンスター表プラス(027ページ)へ移動",
  203. "アンデッドの群れ(基本156ページ)",
  204. "盗賊の群れ(基本156ページ)",
  205. MoveToTable.new("希少動物表(基本156ページ)へ移動", "RANI"),
  206. ]
  207. ),
  208. "MONFT" => DiceTable::D66Table.new(
  209. "モンスター特徴表",
  210. D66SortType::ASC,
  211. {
  212. 11 => "【エッチな】",
  213. 12 => "【変態の】",
  214. 13 => "【弱そうな】",
  215. 14 => "【目のいい】",
  216. 15 => "【目の悪い】",
  217. 16 => "【強そうな】",
  218. 22 => "【強そうな】",
  219. 23 => "【宝石好きな】",
  220. 24 => "【幻の】",
  221. 25 => "【違法な】",
  222. 26 => "【イカした】",
  223. 33 => "【物持ちの】",
  224. 34 => "【炎を吐く】",
  225. 35 => "【必中の】",
  226. 36 => "【すばやい】",
  227. 44 => "【やたら硬い】",
  228. 45 => "【名の知れた】",
  229. 46 => "【凶悪な】",
  230. 55 => "【賞金首の】",
  231. 56 => "【古代種の】",
  232. 66 => "【最強の】",
  233. }
  234. ),
  235. "MONFTP" => DiceTable::D66Table.new(
  236. "モンスター特徴表プラス",
  237. D66SortType::ASC,
  238. {
  239. 11 => "【エッチな】(基本178ページ)",
  240. 12 => "【変態の】(基本178ページ)",
  241. 13 => "【目のいい】(基本178ページ)",
  242. 14 => "【目の悪い】(基本178ページ)",
  243. 15 => "【強そうな】(基本178ページ)",
  244. 16 => "【宝石好きな】(基本178ページ)",
  245. 22 => "【幻の】(基本178ページ)",
  246. 23 => "【違法な】(基本178ページ)",
  247. 24 => "【イカした】(基本178ページ)",
  248. 25 => "【物持ちの】(基本178ページ)",
  249. 26 => "【炎を吐く】(基本178ページ)",
  250. 33 => "【やたら硬い】(基本178ページ)",
  251. 34 => "【古代種の】(基本178ページ)",
  252. 35 => "【最強の】(基本178ページ)",
  253. 36 => "【異国風の】(047ページ)",
  254. 44 => "【毛深い】(047ページ)",
  255. 45 => "【耐火の】(047ページ)",
  256. 46 => "【耐雷の】(047ページ) ",
  257. 55 => "【浮遊の】(047ページ)",
  258. 56 => "【臭い】(047ページ)",
  259. 66 => "【恐怖の】(047ページ)",
  260. }
  261. ),
  262. "RANI" => DiceTable::RangeTable.new(
  263. "希少動物表",
  264. "1D6",
  265. [
  266. [1, "【『緑の森』隊長】1体と遭遇する。今回のセッションで【雪ウサギ】【山岳ゴート】【遺跡白馬】【草原カワウソ】【砂漠キツネ】のいずれかを倒したことがあれば、戦闘が発生する。戦闘にならなかった場合はなごやかに別れる。"],
  267. [2..3, "【『緑の森』団員】1体と遭遇する。今回のセッションで【雪ウサギ】【山岳ゴート】【遺跡白馬】【草原カワウソ】【砂漠キツネ】のいずれかを倒したことがあれば、戦闘が発生する。戦闘にならなかった場合はなごやかに別れる。"],
  268. [4..6, "地形によって異なる希少動物が1体出現する。雪原なら【雪ウサギ】、山岳なら【山岳ゴート】、遺跡なら【遺跡白馬】、草原なら【草原カワウソ】、砂漠と荒野は【砂漠キツネ】。それ以外は【緑の森団員】となる。戦闘を挑んでもいいし、見送ってもいい。"]
  269. ]
  270. ),
  271. "DROP" => DiceTable::ChainTable.new(
  272. "ドロップアイテム表",
  273. "1D6",
  274. [
  275. MoveToTable.new("武器ドロップ表へ移動", "DROPWP"),
  276. MoveToTable.new("武器ドロップ表へ移動", "DROPWP"),
  277. MoveToTable.new("防具ドロップ表へ移動", "DROPAR"),
  278. MoveToTable.new("食品ドロップ表へ移動", "DROPFD"),
  279. MoveToTable.new("巻物ドロップ表へ移動", "DROPSC"),
  280. MoveToTable.new("その他ドロップ表へ移動", "DROPOT"),
  281. ]
  282. ),
  283. "DROPWP" => DiceTable::D66Table.new(
  284. "武器ドロップ表",
  285. D66SortType::ASC,
  286. {
  287. 11 => "【さびた小剣】",
  288. 12 => "【さびた長剣】",
  289. 13 => "【さびた大剣】",
  290. 14 => "【長い棒】",
  291. 15 => "【ダガー】",
  292. 16 => "【木こりの大斧】",
  293. 22 => "【ショートブレイド】",
  294. 23 => "【木の杖】",
  295. 24 => "【狩人の弓】",
  296. 25 => "【レイピア】",
  297. 26 => "【携帯弓】",
  298. 33 => "【ロングブレイド】",
  299. 34 => "【スレンドスピア】",
  300. 35 => "【バトルアックス】",
  301. 36 => "【軍用剛弓】",
  302. 44 => "【グランドブレイド】",
  303. 45 => "【祈りの杖】",
  304. 46 => "【ヘビィボウガン】",
  305. 55 => "【シルバーランス】",
  306. 56 => "【イーグルブレイド】",
  307. 66 => "【クレセントアクス】"
  308. }
  309. ),
  310. "DROPAR" => DiceTable::D66Table.new(
  311. "防具ドロップ表",
  312. D66SortType::ASC,
  313. {
  314. 11 => "【旅人の服】",
  315. 12 => "【旅人の服】",
  316. 13 => "【旅人の服】",
  317. 14 => "【レザーシールド】",
  318. 15 => "【レザーシールド】",
  319. 16 => "【騎士のコート】",
  320. 22 => "【騎士のコート】",
  321. 23 => "【スケイルシールド】",
  322. 24 => "【スケイルシールド】",
  323. 25 => "【レザーベスト】",
  324. 26 => "【レザーベスト】",
  325. 33 => "【ヘビィシールド】",
  326. 34 => "【チェインクロス】",
  327. 35 => "【チェインクロス】",
  328. 36 => "【試練の腕輪】",
  329. 44 => "【精霊のローブ】",
  330. 45 => "【必殺の腕輪】",
  331. 46 => "【ギガントプレート】",
  332. 55 => "【破壊の腕輪】",
  333. 56 => "【理力の腕輪】",
  334. 66 => "【加速の腕輪】"
  335. }
  336. ),
  337. "DROPHW" => DiceTable::Table.new(
  338. "聖武具ドロップ表",
  339. "2D6",
  340. [
  341. "【紅き太陽の剣】",
  342. "【紅き太陽の剣】",
  343. "【聖剣カレドヴルフ】 ",
  344. "【聖斧エルサーベス】 ",
  345. "【水霊のマント】",
  346. "【大地の鎧】",
  347. "【大気の盾】",
  348. "【聖弓ル・アルシャ】",
  349. "【聖槍ヴァルキウス】",
  350. "【聖なる月の剣】",
  351. "【聖なる月の剣】"
  352. ]
  353. ),
  354. "DROPFD" => DiceTable::D66Table.new(
  355. "食品ドロップ表",
  356. D66SortType::ASC,
  357. {
  358. 11 => "【枯れた草】",
  359. 12 => "【こげた草】",
  360. 13 => "【サボテンの肉】",
  361. 14 => "【動物の肉】",
  362. 15 => "【癒しの草】、地形が火山なら【こげた草】",
  363. 16 => "【癒しの草】、地形が火山なら【こげた草】、地形が雪原なら【スノークリスタ草】",
  364. 22 => "【スタミナ草】、地形が火山なら【こげた草】",
  365. 23 => "【スタミナ草】、地形が火山なら【こげた草】、地形が雪原なら【スノークリスタ草】",
  366. 24 => "【触手の草】、地形が火山なら【こげた草】",
  367. 25 => "【触手の草】、地形が火山なら【こげた草】、地形が雪原なら【スノークリスタ草】",
  368. 26 => "【スタミナのアンプル】",
  369. 33 => "【癒しのアンプル】",
  370. 34 => "【癒しのアンプル】",
  371. 35 => "【ナユタの実】、地形が火山なら【こげた草】",
  372. 36 => "【ナユタの実】、地形が火山なら【こげた草】",
  373. 44 => "【火炎のアンプル】",
  374. 45 => "【強酸のアンプル】",
  375. 46 => "【とぶクスリ】",
  376. 55 => "【竜炎のアンプル】",
  377. 56 => "【おいしいお弁当】",
  378. 66 => "【自然治癒のアンプル】"
  379. }
  380. ),
  381. "DROPSC" => DiceTable::D66Table.new(
  382. "巻物ドロップ表",
  383. D66SortType::ASC,
  384. {
  385. 11 => "【石壁の巻物】",
  386. 12 => "【石壁の巻物】",
  387. 13 => "【周辺の地図】",
  388. 14 => "【周辺の地図】",
  389. 15 => "【周辺の地図】",
  390. 16 => "【火炎付与の巻物】",
  391. 22 => "【混乱の巻物】",
  392. 23 => "【剣の巻物】",
  393. 24 => "【剣の巻物】",
  394. 25 => "【鎧の巻物】",
  395. 26 => "【鎧の巻物】",
  396. 33 => "【応急修理の巻物】",
  397. 34 => "【応急修理の巻物】",
  398. 35 => "【移動不能付与の巻物】",
  399. 36 => "【移動不能付与の巻物】",
  400. 44 => "【宝の地図】",
  401. 45 => "【宝の地図】",
  402. 46 => "【召喚の巻物】",
  403. 55 => "【剣の王の巻物】",
  404. 56 => "【守りの神の巻物】",
  405. 66 => "【高度修復の巻物】"
  406. }
  407. ),
  408. "DROPOT" => DiceTable::D66Table.new(
  409. "その他ドロップ表",
  410. D66SortType::ASC,
  411. {
  412. 11 => "【大きな石】、地形が火山なら【くすんだ宝石】",
  413. 12 => "【大きな石】、地形が火山なら【くすんだ宝石】",
  414. 13 => "【大きな石】、地形が火山なら【美しい宝石】",
  415. 14 => "【木製の矢】",
  416. 15 => "【理力の矢】",
  417. 16 => "【鉄製の矢】",
  418. 22 => "【投げナイフ】",
  419. 23 => "【爆弾矢】",
  420. 24 => "【くすんだ宝石】",
  421. 25 => "【盾修復キット】",
  422. 26 => "【上質の研ぎ石】",
  423. 33 => "【エルザイト爆弾】",
  424. 34 => "【セーブクリスタル】",
  425. 35 => "【試練の腕輪】",
  426. 36 => "【必殺の腕輪】",
  427. 44 => "【破壊の腕輪】",
  428. 45 => "【理力の腕輪】",
  429. 46 => "【加速の腕輪】",
  430. 55 => "【美しい宝石】",
  431. 56 => "【封印のカギ】",
  432. 66 => "【闇ギルド会員証】"
  433. }
  434. ),
  435. "DROPP" => DiceTable::D66Table.new(
  436. "ドロップアイテム表プラス",
  437. D66SortType::ASC,
  438. {
  439. 11 => MoveToTable.new("武器ドロップ表", "DROPWP"),
  440. 12 => MoveToTable.new("武器ドロップ表", "DROPWP"),
  441. 13 => MoveToTable.new("武器ドロップ表2", "DROPWP2"),
  442. 14 => MoveToTable.new("武器ドロップ表2", "DROPWP2"),
  443. 15 => MoveToTable.new("防具ドロップ表", "DROPAR"),
  444. 16 => MoveToTable.new("防具ドロップ表", "DROPAR"),
  445. 22 => MoveToTable.new("防具ドロップ表2", "DROPAR2"),
  446. 23 => MoveToTable.new("防具ドロップ表2", "DROPAR2"),
  447. 24 => MoveToTable.new("食品ドロップ表", "DROPFD"),
  448. 25 => MoveToTable.new("食品ドロップ表", "DROPFD"),
  449. 26 => MoveToTable.new("食品ドロップ表2", "DROPFD2"),
  450. 33 => MoveToTable.new("食品ドロップ表2", "DROPFD2"),
  451. 34 => MoveToTable.new("薬品ドロップ表プラス", "DROPDRP"),
  452. 35 => MoveToTable.new("薬品ドロップ表プラス", "DROPDRP"),
  453. 36 => MoveToTable.new("巻物ドロップ表", "DROPSC"),
  454. 44 => MoveToTable.new("巻物ドロップ表", "DROPSC"),
  455. 45 => MoveToTable.new("巻物ドロップ表2", "DROPSC2"),
  456. 46 => MoveToTable.new("巻物ドロップ表2", "DROPSC2"),
  457. 55 => MoveToTable.new("その他ドロップ表", "DROPOT"),
  458. 56 => MoveToTable.new("その他ドロップ表", "DROPOT"),
  459. 66 => MoveToTable.new("その他ドロップ表2", "DROPOT2")
  460. }
  461. ),
  462. "DROPDRP" => DiceTable::D66Table.new(
  463. "薬品ドロップ表プラス",
  464. D66SortType::ASC,
  465. {
  466. 11 => "【燃料油のビン】",
  467. 12 => "【燃料油のビン】",
  468. 13 => "【燃料油のビン】",
  469. 14 => "【弱体の薬】",
  470. 15 => "【弱体の薬】",
  471. 16 => "【弱体の薬】",
  472. 22 => "【成長の薬】",
  473. 23 => "【ベルセルクアンプル】",
  474. 24 => "【ベルセルクアンプル】",
  475. 25 => "【浮遊の薬】",
  476. 26 => "【浮遊の薬】",
  477. 33 => "【反動解消の薬】",
  478. 34 => "【反動解消の薬】",
  479. 35 => "【癒しの大ボトル】",
  480. 36 => "【癒しの大ボトル】",
  481. 44 => "【超元気のアンプル】",
  482. 45 => "【超元気のアンプル】",
  483. 46 => "【薬命酒】",
  484. 55 => "【薬命酒】",
  485. 56 => "【洗脳のクスリ】",
  486. 66 => "【洗脳のクスリ】"
  487. }
  488. ),
  489. "DROPSC2" => DiceTable::D66Table.new(
  490. "巻物ドロップ表2",
  491. D66SortType::ASC,
  492. {
  493. 11 => "【火炎波の巻物】",
  494. 12 => "【悟りの巻物】",
  495. 13 => "【理盾の巻物】",
  496. 14 => "【泉の巻物】",
  497. 15 => "【雷神の巻物】",
  498. 16 => "【超激震の巻物】",
  499. 22 => "【闇を阻む巻物】",
  500. 23 => "【引きこもりの巻物】",
  501. 24 => "【鋼鉄の巻物】",
  502. 25 => "【回廊の巻物】",
  503. 26 => "【騎士団の巻物】",
  504. 33 => "【水泳能力の巻物】",
  505. 34 => "【浮遊能力の巻物】",
  506. 35 => "【治癒の書】",
  507. 36 => "【浮遊の書】",
  508. 44 => "【突風の書】",
  509. 45 => "【睡眠の書】",
  510. 46 => "【火炎の書】",
  511. 55 => "【鋼鉄の書】",
  512. 56 => "【加速の書】",
  513. 66 => "【闇払いの書】"
  514. }
  515. ),
  516. "DROPWP2" => DiceTable::D66Table.new(
  517. "武器ドロップ表2",
  518. D66SortType::ASC,
  519. {
  520. 11 => "【さびた巨大斧】",
  521. 12 => "【さびた巨大斧】",
  522. 13 => "【モコモコのバトン】",
  523. 14 => "【モコモコのバトン】",
  524. 15 => "【ベルセルクアクス】",
  525. 16 => "【ベルセルクアクス】",
  526. 22 => "【クナイ】",
  527. 23 => "【クナイ】",
  528. 24 => "【術殺槍】",
  529. 25 => "【ウィンドスピア】",
  530. 26 => "【ウィンドスピア】",
  531. 33 => "【つるはし】",
  532. 34 => "【つるはし】",
  533. 35 => "【理力の剣】",
  534. 36 => "【蒼い短刀】",
  535. 44 => "【クリムゾンクロウ】",
  536. 45 => "【ナユタの杖】",
  537. 46 => "【ナユタの杖】",
  538. 55 => "【一撃斧】",
  539. 56 => "【ファイアブランド】",
  540. 66 => "【ソードクロスボウ】"
  541. }
  542. ),
  543. "DROPAR2" => DiceTable::D66Table.new(
  544. "防具ドロップ表2",
  545. D66SortType::ASC,
  546. {
  547. 11 => "【ボロボロの服】",
  548. 12 => "【ボロボロの服】",
  549. 13 => "【穴だらけの鎧】",
  550. 14 => "【穴だらけの鎧】",
  551. 15 => "【木製の追加装甲】",
  552. 16 => "【木製の追加装甲】",
  553. 22 => "【ガラスの鎧】",
  554. 23 => "【ガラスの鎧】",
  555. 24 => "【鉄板の追加装甲】",
  556. 25 => "【鉄板の追加装甲】",
  557. 26 => "【太陽のランタン】",
  558. 33 => "【耐火服】",
  559. 34 => "【獣の革のバッグ】",
  560. 35 => "【重量ブーツ】",
  561. 36 => "【冒険者のブーツ】",
  562. 44 => "【ラバーブーツ】",
  563. 45 => "【風のマント】",
  564. 46 => "【狩人の服】",
  565. 55 => "【ドラゴンスケイル】",
  566. 56 => "【不育の腕輪】",
  567. 66 => "【竜革の大きなバッグ】"
  568. }
  569. ),
  570. "DROPHWP" => DiceTable::D66Table.new(
  571. "聖武具ドロップ表プラス",
  572. D66SortType::ASC,
  573. {
  574. 11 => "【大気の盾】",
  575. 23 => "【聖剣カレドヴルフ】",
  576. 36 => "【紅蓮の書】",
  577. 12 => "【大気の盾】",
  578. 24 => "【聖斧エルサーベス】",
  579. 44 => "【聖弓ル・アルシャ】",
  580. 13 => "【大地の鎧】",
  581. 25 => "【聖斧エルサーベス】",
  582. 45 => "【聖弓ル・アルシャ】",
  583. 14 => "【大地の鎧】",
  584. 26 => "【聖槍ヴァルキウス】",
  585. 46 => "【聖なる月の剣】",
  586. 15 => "【水霊のマント】",
  587. 33 => "【聖槍ヴァルキウス】",
  588. 55 => "【紅き太陽の剣】",
  589. 16 => "【水霊のマント】",
  590. 34 => "【聖槍ヴァルキウス】",
  591. 56 => "【嵐の聖剣】",
  592. 22 => "【聖剣カレドヴルフ】",
  593. 35 => "【紅蓮の書】",
  594. 66 => "【超重の聖斧】"
  595. }
  596. ),
  597. "DROPFD2" => DiceTable::Table.new(
  598. "食品ドロップ表2",
  599. "1D6",
  600. [
  601. "【解毒の草】、地形が火 山なら【こげた草】、地 形が海岸なら【おいし い海藻】",
  602. "【気付けの草】、地形が 火山なら【こげた草】、 地形が海岸なら【おい しい海藻】",
  603. "【夜目の草】",
  604. "【力が湧く草】",
  605. "【集中の草】",
  606. "【牛乳】"
  607. ]
  608. ),
  609. "DROPOT2" => DiceTable::Table.new(
  610. "その他 ドロップ表2",
  611. "2D6",
  612. [
  613. "【五連の矢】",
  614. "【炎の矢】",
  615. "【聖なる投げ刃】",
  616. "【物体破壊爆弾】",
  617. "【閃光弾】",
  618. "【聖なる短剣の破片】",
  619. "【閃光弾】",
  620. "【旋風の投げ刃】",
  621. "【スーパーエルザイト 爆弾】",
  622. "【炎の矢】",
  623. "【五連の矢】"
  624. ]
  625. ),
  626. "DROPRAREBOX2" => DiceTable::Table.new(
  627. "珍しい箱ドロップ表2",
  628. "2D6",
  629. [
  630. "聖武具ドロップ表プラ スへ",
  631. "【耐久力の結晶】",
  632. "【偉大な筋力の結晶】",
  633. "【偉大な敏捷の結晶】",
  634. "【偉大な生命の結晶】",
  635. "【竜鱗の追加装甲】",
  636. "【偉大な魅力の結晶】",
  637. "【偉大な意志の結晶】",
  638. "【偉大な知力の結晶】",
  639. "【スタミナの結晶】",
  640. "【闇払いの書】"
  641. ]
  642. ),
  643. "KNGFTP" => DiceTable::Table.new(
  644. "王特徴表プラス",
  645. "1D6",
  646. [
  647. "【力の王の】(047ページ)",
  648. "【力の王の】(047ページ)",
  649. "【疾風の王の】(047ページ)",
  650. "【疾風の王の】(047ページ)",
  651. "【炎の王の】(047ページ)",
  652. "【絶望の王の】(047ページ)"
  653. ]
  654. ),
  655. }.freeze
  656. end
  657. end
  658. end

lib/bcdice/game_system/satasupe/tables.rb

40.0% lines covered

100.0% branches covered

30 relevant lines. 12 lines covered and 18 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class Satasupe < Base
  5. 1 TAG_TABLE = DiceTable::D66GridTable.new(
  6. "タグ決定表",
  7. [
  8. ["情報イベント", "エクストリーム(サ)", "カワイイ(サ)", "トンデモ(サ)", "マニア(サ)", "ヲタク(サ)"],
  9. ["音楽(ア)", "好きなタグ", "トレンド(ア)", "読書(ア)", "パフォーマンス(ア)", "美術(ア)"],
  10. ["アラサガシ(マ)", "おせっかい(マ)", "好きなタグ", "家事(マ)", "ガリ勉(マ)", "健康(マ)"],
  11. ["アウトドア(休)", "工作(休)", "スポーツ(休)", "同一タグ", "ハイソ(休)", "旅行(休)"],
  12. ["育成(イ)", "サビシガリヤ(イ)", "ヒマツブシ(イ)", "宗教(イ)", "同一タグ", "ワビサビ(イ)"],
  13. ["アダルト(風)", "飲食(風)", "ギャンブル(風)", "ゴシップ(風)", "ファッション(風)", "情報ハプニング"],
  14. ]
  15. )
  16. CREATE_ARMS_ACCESSORY_TABLE = {
  17. 6 11 => ["「パチンコ玉」", "「武器破壊」", lambda { |arm, _r| arm.abilities << "「武器破壊」" }].freeze,
  18. 12 => ["「釘や画鋲、針」", "「毒」", lambda { |arm, _r| arm.abilities << "「毒」" }].freeze,
  19. 13 => ["「砂利や小石、ガラスの破片」", "「散弾」", lambda { |arm, _r| arm.abilities << "「散弾」" }].freeze,
  20. 14 => ["「口紅」", "「(判定前宣言)一度だけ必殺10」", lambda { |arm, _r| arm.kutibeni += 1 }].freeze,
  21. 15 => ["「バネやゼンマイ」", "「フル」", lambda { |arm, _r| arm.abilities << "「フル」" }].freeze,
  22. 16 => ["「捻子やビス」", "「ダメージ+1」", lambda { |arm, _r| arm.damage += 1 }].freeze,
  23. 22 => ["「生ゴミ」", "「衝撃」", lambda { |arm, _r| arm.abilities << "「衝撃」" }].freeze,
  24. 23 => ["「ゴム」", "「ダメージ+1」", lambda { |arm, _r| arm.damage += 1 }].freeze,
  25. 24 => ["「歯車」", "「リボルバー」", lambda { |arm, _r| arm.abilities << "「リボルバー」" }].freeze,
  26. 1 25 => ["「歯や牙、骨」", "「(判定前宣言)1D6回、ダメージ+2」", lambda { |arm, r| arm.kiba = r.roll_once(6) }].freeze,
  27. 26 => ["「ワイヤー」", "「耐久度+1」", lambda { |arm, _r| arm.life += 1 }].freeze,
  28. 33 => ["「メガネなどのレンズ」", "「命中-1」", lambda { |arm, _r| arm.hit -= 1 }].freeze,
  29. 34 => ["「マッチ」", "「必殺12」", lambda { |arm, _r| arm.abilities << "「必殺12」" }].freeze,
  30. 35 => ["「ガムテープや接着剤」", "「耐久度+1」", lambda { |arm, _r| arm.life += 1 }].freeze,
  31. 36 => ["「洗濯ばさみ」", "「命中-1」", lambda { |arm, _r| arm.hit -= 1 }].freeze,
  32. 44 => ["「花火」", "「弾幕1」", lambda { |arm, _r| arm.abilities << "「弾幕1」" }].freeze,
  33. 45 => ["「食玩」", "「暗器」", lambda { |arm, _r| arm.abilities << "「暗器」" }].freeze,
  34. 46 => ["「真空管やトランジスタ」", "「神秘」", lambda { |arm, _r| arm.abilities << "「神秘」" }].freeze,
  35. 55 => ["「エアコンプレッサ」", "「ダメージ+1」", lambda { |arm, _r| arm.damage += 1 }].freeze,
  36. 56 => ["「豆」", "「マヒ」", lambda { |arm, _r| arm.abilities << "「マヒ」" }].freeze,
  37. 3 66 => ["「ガスボンベや殺虫剤」", "「爆発3」", lambda { |arm, _r| arm.abilities << "「爆発3」" }].freeze,
  38. }.freeze
  39. NPC_AGE_TABLE = [ # 年齢表
  40. 1 ["幼年", 6, 2].freeze, # 6+2D6歳
  41. ["少年", 10, 2].freeze, # 10+2D6歳
  42. ["青年", 15, 3].freeze, # 15+3D6歳
  43. ["中年", 25, 4].freeze, # 25+4D6歳
  44. ["壮年", 40, 5].freeze, # 40+5D6歳
  45. ["老年", 60, 6].freeze, # 60+6D6歳
  46. ].freeze
  47. 1 NPC_LMOOD_TABLE = [ # 好み/雰囲気表
  48. "ダークな",
  49. "お金持ちな",
  50. "美形な",
  51. "知的な",
  52. "ワイルドな",
  53. "バランスがとれてる",
  54. ].freeze
  55. 1 NPC_LAGE_TABLE = [ # 好み/年齢表
  56. "年下が好き。",
  57. "同い年が好き。",
  58. "年上が好き。",
  59. ].freeze
  60. TABLES = {
  61. 1 "CrimeIET" => DiceTable::Table.new(
  62. "情報イベント表/〔犯罪〕",
  63. "2D6",
  64. [
  65. "謎の情報屋チュンさん登場。ターゲットとなる情報を渡し、いずこかへ去る。情報ゲット!",
  66. "昔やった仕事の依頼人が登場。てがかりをくれる。好きなタグの上位リンク(SL+2)を1つ得る。",
  67. "謎のメモを発見……このターゲットについて調べている間、このトピックのタグをチーム全員が所有しているものとして扱う",
  68. "謎の動物が亜侠を路地裏に誘う。好きなタグの上位リンクを2つ得る",
  69. "偶然、他の亜侠の仕事現場に出くわす。口止め料の代わりに好きなタグの上位リンクを1つ得る",
  70. "あまりに適切な諜報活動。コストを消費せず、上位リンクを3つ得る",
  71. "その道の権威を紹介される。現在と同じタグの上位リンクを2つ得る",
  72. "捜査は足だね。〔肉体点〕を好きなだけ消費する。その値と同じ数の好きなタグの上位リンクを得る",
  73. "近所のコンビニで立ち読み。思わぬ情報が手に入る。上位リンクを3つ得る",
  74. "そのエリアの支配盟約からメッセンジャーが1D6人。自分のチームがその盟約に敵対していなければ、好きなタグの上位リンクを2つ得る。敵対していれば、メッセンジャーは「盟約戦闘員(p.127)」となる。血戦を行え",
  75. "「三下(p.125)」が1D6人現れる。血戦を行え。倒した数だけ、好きなタグの上位リンクを手に入れる"
  76. ]
  77. ),
  78. "LifeIET" => DiceTable::Table.new(
  79. "情報イベント表/〔生活〕",
  80. "2D6",
  81. [
  82. "謎の情報屋チュンさん登場。ターゲットとなる情報を渡し、いずこかへ去る。情報ゲット!",
  83. "隣の奥さんと世間話。上位リンクを4つ得る",
  84. "ミナミで接待。次の1ターン何もできない代わりに、好きなタグの上位リンク(SL+2)を1つ得る",
  85. "息抜きにテレビを見ていたら、たまたまその情報が。好きなタグの上位リンクを1つ得る",
  86. "器用に手に入れた情報を転売する。《札巻》を1個手に入れ、上位リンクを3つ得る",
  87. "情報を得るついでに軽い営業。〔サイフ〕を1回復させ、上位リンクを3つ得る",
  88. "街の有力者からの突然の電話。そのエリアの盟約の幹部NPCの誰かと【コネ】を結ぶことができる",
  89. "金をばらまく。〔サイフ〕を好きなだけ消費する。その値と同じ数の任意の上位リンクを得る",
  90. "〔表の顔〕の同僚が思いがけないアドバイスをくれる。上位リンクを1D6つ得る",
  91. "謎の情報屋チュンさんが、情報とアイテムのトレードを申し出る。DDの指定するアイテムを1つ手に入れると、どこからともなくチュンさんが現れる。そのアイテムをチュンさんに渡せば、情報ゲット!",
  92. "ターゲットとは関係ないが、ドデかい情報を掘り当てる。その情報を売って〔サイフ〕が全快する"
  93. ]
  94. ),
  95. "LoveIET" => DiceTable::Table.new(
  96. "情報イベント表/〔恋愛〕",
  97. "2D6",
  98. [
  99. "謎の情報屋チュンさん登場。ターゲットとなる情報を渡し、いずこかへ去る。情報ゲット!",
  100. "恋人との別れ。自分に恋人がいれば、1人を選んで、お互いのトリコ欄から名前を消す。その代わり情報ゲット!",
  101. "とびきり美形の情報提供者と遭遇。〔性業値〕判定で律になると、好きなタグの上位リンクを1つ得る",
  102. "敵対する亜侠と第一種接近遭遇。キスのあとの濡れた唇から、上位リンクを3つ得る",
  103. "昔の恋人がそれに詳しかったはず。その日の深夜・早朝に行動しなければ、好きなタグの上位リンク(SL+2)を1つ得る",
  104. "情報はともかくトリコをゲット。データは「女子高生(p.122)」を使用する",
  105. "関係者とすてきな時間を過ごす。好きなタグの上位リンクを1つ得る。ただし、次の1ターンは行動できない",
  106. "持つべきものは愛の奴隷。自分のトリコの数だけ好きなタグの上位リンクを得る",
  107. "自分よりも10歳年上のイヤなやつに身体を売る。現在と同じタグの上位リンクを1つ得る",
  108. "有力者からの突然のご指名。チームの仲間を1人、ランダムに決定する。差し出すなら、そのキャラクターは次の1ターン行動できない代わり、その後にそのキャラクターの〔恋愛〕と同じ数の上位リンクを得る",
  109. "愛する人の死。自分に恋人がいれば、1人選んで、そのキャラクターを死亡させる。その代わり情報ゲット!"
  110. ]
  111. ),
  112. "CultureIET" => DiceTable::Table.new(
  113. "情報イベント表/〔教養〕",
  114. "2D6",
  115. [
  116. "謎の情報屋チュンさん登場。ターゲットとなる情報を渡し、いずこかへ去る。情報ゲット!",
  117. "ネットで幻のリンクサイトを発見。すべての種類のタグに上位リンクがはられる",
  118. "間違いメールから恋が始まる。ハンドルしか知らない「女子高生(p.122)」と恋人(お互いのトリコ)の関係になる",
  119. "新聞社でバックナンバーを読みふける。上位リンクを6つ得る",
  120. "巨大な掲示板群から必要な情報をサルベージ。好きなタグの上位リンクを1つ得る",
  121. "検索エンジンにかけたらすぐヒット。コストを消費せず、上位リンクを4つ得る",
  122. "警察無線を傍受。興味深い。好きなタグの上位リンクを2つ得る",
  123. "クールな推理がさえ渡る。〔精神点〕を好きなだけ消費する。その値と同じ数だけ好きなタグの上位リンクを得る",
  124. "図書館ロールが貫通。好きなタグの上位リンク(SL+3)を1つ得る",
  125. "図書館で幻の書物を発見。上位リンクを8つ得る。キャラクターシートのメモ欄に<クトゥルフ神話知識>、SANと記入し、それぞれ後ろに+5、-5の数値を書き加える",
  126. "アジトに謎の手紙が届く。自分のアジトに戻れば、情報ゲット!"
  127. ]
  128. ),
  129. "CombatIET" => DiceTable::Table.new(
  130. "情報イベント表/〔戦闘〕",
  131. "2D6",
  132. [
  133. "謎の情報屋チュンさん登場。ターゲットとなる情報を渡し、いずこかへ去る。情報ゲット!",
  134. "昔、お前が『更正』させた大幇のチンピラから情報を得る。〔精神点〕を2点減少し、好きなタグの上位リンク(SL+2)を1つ得る。",
  135. "大阪市警の刑事から情報リーク。「敵の敵は味方」ということか……? 〔精神点〕を3点減少し、上位リンクを6つ得る。",
  136. "無軌道な若者達を拳で『更正』させる。彼等は涙を流しながら情報を差し出した。……情けは人のためならず。好きなだけ〔精神点〕を減少する。減少した値と同じ数だけ、上位リンクを得る。",
  137. "クスリ漬けの流氓を拳で『説得』。流氓はゲロと一緒に情報を吐き出した。2点のダメージ(セーブ不可)を受け、好きなタグの上位リンクを1つ得る。",
  138. "次から次へと糞どもがやってくる。コストを消費せずに上位リンクを3つ得る。",
  139. "自称『善良な一市民』からの情報リークを受ける。オマエの持っている異能の数だけ上位リンクを得る。……罠か!?",
  140. "サウナ風呂でくつろぐヤクザから情報収集。ヤクザは歯の折れた口から、弱々しい呻きと共に情報を吐き出した。好きなだけダメージを受ける(セーブ不可)。好きなタグの受けたダメージと同じ値のSLへリンクを1つ得る。",
  141. "ゼロ・トレランスオンスロートなラブ&ウォー。2D6を振り、その値が現在の〔肉体点〕以上であれば、情報をゲット!",
  142. "お前達を狙う刺客が冥土の土産に教えてくれる。お前自身かチームの仲間、お前の恋人のいずれかの〔肉体点〕を0点にすれば、情報をゲットできる。",
  143. "お前の宿敵(データはブラックアドレス)が1D6体現れる。血戦によって相手を倒せば、情報ゲット。"
  144. ]
  145. ),
  146. "CrimeIHT" => DiceTable::Table.new(
  147. "情報ハプニング表/〔犯罪〕",
  148. "2D6",
  149. [
  150. "謎の情報屋チュンさん登場。ターゲットとなる情報を渡し、いずこかへ去る。情報ゲット!",
  151. "警官からの職務質問。一晩拘留される。臭い飯表(p.70)を1回振ること",
  152. "だますつもりがだまされる。〔サイフ〕を1点消費",
  153. "気のゆるみによる駐車違反。持っている乗物が無くなってしまう",
  154. "超えてはならない一線を越える。トラウマを1点受ける",
  155. "そのトピックを取りしきる盟約に目をつけられる。このトピックと同じタグのトピックからはリンクをはれなくなる",
  156. "過去の亡霊がきみを襲う。自分の修得している異能の中から好きな1つを選ぶ。このセッションでは、その異能が使用不可になる",
  157. "敵対する盟約のいざこざに巻き込まれる。〔肉体点〕に1D6点のセーブ不可なダメージを受ける",
  158. "スリにあう。〔通常装備〕からランダムにアイテムを1個選び、それを無くす",
  159. "敵対する盟約からの妨害工作。この情報は情報収集のルールを使って手に入れることはできなくなる",
  160. "頼れる協力者のもとへ行くと、彼(彼女)の無惨な姿が……自分の持っている現在のセッションに参加していないキャラクター1体を選び、〔肉体点〕を0にする。そして、致命傷表(p.61)を振ること"
  161. ]
  162. ),
  163. "LifeIHT" => DiceTable::Table.new(
  164. "情報ハプニング表/〔生活〕",
  165. "2D6",
  166. [
  167. "謎の情報屋チュンさん登場。ターゲットとなる情報を渡し、いずこかへ去る。情報ゲット!",
  168. "経理の整理に没頭。この日の行動をすべてそれに費やさない限り、このセッションでは買物を行えなくなる",
  169. "壮大なる無駄使い。〔サイフ〕を1点消費",
  170. "「当たり屋(p.124)」が【追跡】を開始",
  171. "留守の間に空き巣が! 〔アジト装備〕からランダムにアイテムが1個無くなる",
  172. "「押し売り(p.124)」が【追跡】を開始",
  173. "新たな風を感じる。自分の好きな〔趣味〕1つをランダムに変更すること",
  174. "貧乏ひまなし。[1D6-自分の〔生活〕]ターンの間、行動できなくなる",
  175. "留守の間にアジトが火事に! 〔アジト装備〕がすべて無くなる。明日からどうしよう?",
  176. "頼りにしていた有力者が失脚する。しわ寄せがこっちにもきて、〔生活〕が1点減少する",
  177. "覚えのない借金の返済を迫られる。〔サイフ〕を1D6点減らす。〔サイフ〕が足りない場合、そのセッション終了時までに不足分を支払わないと【借金大王】(p.119)の代償を得る"
  178. ]
  179. ),
  180. "LoveIHT" => DiceTable::Table.new(
  181. "情報ハプニング表/〔恋愛〕",
  182. "2D6",
  183. [
  184. "謎の情報屋チュンさん登場。ターゲットとなる情報を渡し、いずこかへ去る。情報ゲット!",
  185. "一晩を楽しむが相手はちょっと特殊な趣味だった。アブノーマルの趣味を持っていない限り、トラウマを1点受ける。この日はもう行動できない",
  186. "一晩を楽しむが相手はちょっと特殊な趣味だった。【両刀使い】の異能を持っていない限り、トラウマを1点受ける。この日はもう行動できない",
  187. "一晩を楽しむが相手は年齢を10偽っていた。ロマンス判定のファンブル表を振ること",
  188. "すてきな人を見かけ、一目惚れ。DDが選んだNPC1体のトリコになる",
  189. "「痴漢・痴女(p.124)」が【追跡】を開始",
  190. "手を出した相手が有力者の女(ヒモ)だった。手下どもに袋叩きに会い、1D6点のダメージを受ける(セーブ不可)",
  191. "突然の別れ。トリコ欄からランダムに1体を選び、その名前を消す",
  192. "乱れた性生活に疲れる。〔肉体点〕と〔精神点〕がともに2点減少する",
  193. "性病が伝染る。1日以内に病院に行き、治療(価格4)を行わないと、鼻がもげる。鼻がもげると〔恋愛〕が1点減少する",
  194. "生命の誕生。子供ができる"
  195. ]
  196. ),
  197. "CultureIHT" => DiceTable::Table.new(
  198. "情報ハプニング表/〔教養〕",
  199. "2D6",
  200. [
  201. "謎の情報屋チュンさん登場。ターゲットとなる情報を渡し、いずこかへ去る。情報ゲット!",
  202. "アヤシイ書物を読み、一時的発狂。この日はもう行動できない。トラウマを1点受ける",
  203. "天才ゆえの憂鬱。自分の〔教養〕と同じ値だけ、〔精神点〕を減少させる",
  204. "唐突に睡魔が。次から2ターンの間、睡眠しなくてはならない",
  205. "間違いメールから恋が始まる。ハンドルしか知らない「女子高生(p.122)」に偽装した「殺人鬼(p.137)」と恋人(お互いのトリコ)の関係になる",
  206. "「勧誘員(p.124)」が【追跡】を開始",
  207. "OSの不調。徹夜で再インストール。この日はもう行動できない上、「無理」をしてしまう",
  208. "場を荒らしてしまう。このトピックと同じタグのトピックからはリンクをはれなくなる",
  209. "ボケる。〔教養〕が1点減少する",
  210. "クラッキングに遭う。いままで調べていたトピックとリンクをすべて失う",
  211. "ネットサーフィンにハマってしまい、ついつい時間が過ぎる。毎ターンのはじめに〔性業値〕判定を行い、律にならないとそのターンは行動できない。この効果は1日続く"
  212. ]
  213. ),
  214. "CombatIHT" => DiceTable::Table.new(
  215. "情報ハプニング表/〔戦闘〕",
  216. "2D6",
  217. [
  218. "謎の情報屋チュンさん登場。ターゲットとなる情報を渡し、いずこかへ去る。情報ゲット!",
  219. "悪を憎む心に支配され、一匹の修羅と化す。キジルシの代償から1種類を選び、このセッションの間、習得すること。修得できるキジルシの代償がなければ、あなたはNPCとなる。",
  220. "自宅に帰ると、無惨に破壊された君のおたからが転がっていた。「この件から手を引け」という書き置きと共に……。この情報フェイズでは、リンク判定を行ったトピックのタグの〔趣味〕を修得していた場合、それを未修得にする。また、おたからを持っていたなら、このセッション中、そのおたからは利用できなくなる。",
  221. "「俺にはもっと別の人生があったんじゃないだろうか……!?」突如、空しさがこみ上げて来る……その日は各ターンの始めに〔性業値〕判定を行う。失敗すると、酒に溺れ、そのターンは行動済みになる。",
  222. "クライムファイター仲間からスパイの容疑を受ける……1点のトラウマを追う。",
  223. "自宅の扉にメモが……!! 「今ならまだ間に合う」奴等はどこまで知っているんだ!? このトピックからは、これ以上リンクを伸ばせなくなる。",
  224. "大幇とコンビナートの抗争に何故か巻き込まれる。……なんとか生還するが、次のターンの最後まで行動できず、1D6点のダメージを受ける(セーブ不可)",
  225. "地獄組の鉄砲玉が君に襲い掛かってきた!! 〔戦闘〕で難易度9の判定に失敗すると、〔肉体点〕が0になる。",
  226. "「お前はやり過ぎた」の書きおきと共に、友人の死体が発見される〔戦闘〕で難易度9の判定を行う。失敗すると、ランダムに選んだチームの仲間1人が死亡する。",
  227. "宿敵によって深い疵を受ける。自分の修得している異能の中から、1つ選ぶこと。このセッションのあいだ、その異能を使用することができなくなる。",
  228. "流氓の男の卑劣な罠にかかり、肥え喰らいの巣に落ちる!! 「掃き溜めの悪魔」1D6体と血戦を行う。戦いに勝たない限り、生きて帰ることはできないだろう……。もちろん血戦に勝ったところで情報は得られない。"
  229. ]
  230. ),
  231. "GeneralAccidentT" => DiceTable::Table.new(
  232. "汎用アクシデント表",
  233. "2D6",
  234. [
  235. "痛恨のミス。激しく状況が悪化する。以降のケチャップに関する行為判定の難易度に+1の修正がつき、あなたが追う側なら逃げる側のコマを2マス進める(逃げる側なら自分を2マス戻す)",
  236. "最悪の大事故。ケチャップどころではない! 〔犯罪〕で難易度9の判定を行う。失敗したら、ムーブ判定を行ったキャラクターは3D6点のダメージを受け、ケチャップから脱落する。判定に成功すればギリギリ難を逃れる。特に何もなし。",
  237. "もうダメだ……。絶望感が襲いかかってくる。後3ラウンド以内にケリをつけないと、あなたが追う側なら自動的に逃げる側が勝利する(逃げる側なら追う側が勝利する)",
  238. "まずい、突発事故だ! ムーブ判定を行ったキャラクターは、1D6点のダメージを受ける。",
  239. "一瞬ひやりと緊張が走る。 ムーブ判定を行ったキャラクターは、〔精神点〕を2点減少する。",
  240. "スランプ! 思わず足踏みしてしまう。ムーブ判定を行った者は、ムーブ判定に使用した能力値を使って難易度7の判定を行うこと。失敗したら、ムーブ判定を行ったキャラクターは、ケチャップから脱落。成功しても、あなたが追う側なら逃げる側のコマを1マス進める(逃げる側なら自分を1マス戻す)",
  241. "イマイチ集中できない。〔性業値〕判定を行うこと。「激」になると、思わず見とれてしまう。あなたが追う側なら逃げる側のコマを1マス進める(逃げる側なら自分を1マス戻す)",
  242. "古傷が痛み出す。以降のケチャップに関する行為判定に修正が+1つく",
  243. "うっかり持ち物を見失う。〔通常装備〕欄からアイテムを1個選んで消す",
  244. "苦しい状態に追い込まれた。ムーブ判定を行ったキャラクターは、今後のムーブ判定で成功度が-1される。",
  245. "頭の中が真っ白になる。〔精神点〕を1D6減少する。"
  246. ]
  247. ),
  248. "RomanceFumbleT" => DiceTable::Table.new(
  249. "ロマンスファンブル表",
  250. "2D6",
  251. [
  252. "みんなあいそをつかす。自分のトリコ欄のキャラクターの名前をすべて消すこと",
  253. "痴漢として通報される。〔犯罪〕の難易度9の判定に成功しない限り、1D6ターン後に検挙されてしまう",
  254. "へんにつきまとわれる。対象は、トリコになるが、ファンブル表の結果やトリコと分かれる判定に成功しない限り、常備化しなくてもトリコ欄から消えることはない",
  255. "修羅場! 対象とは別にトリコを所有していれば、そのキャラクターが現れ、あなたと対象に血戦をしかけてくる",
  256. "恋に疲れる。自分の〔精神点〕が1D6点減少する",
  257. "甘い罠。あなたが対象のトリコになってしまう",
  258. "平手うち! 自分の〔肉体点〕が1D6点減少する",
  259. "浮気がばれる。恋人関係にあるトリコがいれば、そのキャラクターの名前をあなたのトリコ欄から消す",
  260. "無礼な失言をしてしまう。対象はあなたに対し「憎悪(p.120参照)」の反応を抱き、あなたはその対象の名前を書き込んだ【仇敵】の代償を得る",
  261. "ショックな一言。トラウマを1点受ける",
  262. "トリコからの監視! このセッションの間、ロマンス判定のファンブル率が自分のトリコの所持数と同じだけ上昇する"
  263. ]
  264. ),
  265. "FumbleT" => DiceTable::Table.new(
  266. "命中判定ファンブル表",
  267. "2D6",
  268. [
  269. "自分の持ち物がすっぽぬけ、偶然敵を直撃! 持っているアイテムを1つ消し、ジオラマ上にいるキャラクター1人をランダムに選ぶ。そのキャラクターの〔肉体点〕を1D6ラウンドの間0点にし、行動不能にさせる(致命傷表は使用しない)。1D6ラウンドが経過し、行動不能から回復すると、そのキャラクターの〔肉体点〕は、行動不能になる直前の値にまで回復する",
  270. "敵の増援! 「三下(p.125)」が1D6体現れて、自分たちに襲いかかってくる(DDは、この処理が面倒だと思ったら、ファンブルしたキャラクターの〔肉体点〕を1D6点減少させてもよい)",
  271. "お前のいるマスに「障害物」が出現! そのマスに障害物オブジェクトを置き、そのマスにいたキャラクターは全員2ダメージを受ける(セーブ不可)",
  272. "射撃武器を使っていれば、弾切れを起こす。準備行動を行わないとその武器はもう使えない",
  273. "転んでしまう。準備行動を行わないと移動フェイズに行動できず、格闘、射撃、突撃攻撃が行えない",
  274. "急に命が惜しくなる。性業値判定をすること。「激」なら戦闘を続行。「律」なら次のラウンドから全力移動を行い、ジオラマから逃走を試みる。「迷」なら次のラウンドは移動・攻撃フェイズに行動できない",
  275. "誤って別の目標を攻撃。目標以外であなたに一番近いキャラクターに4ダメージ(セーブ不可)!",
  276. "誤って自分を攻撃。3ダメージ(セーブ不可)!",
  277. "今使っている武器が壊れる。アイテム欄から使用中の武器を消すこと。銃器を使っていた場合、暴発して自分に6ダメージ! 武器なしの場合、体を傷つけ3ダメージ(共にセーブ不可)!",
  278. "「制服警官(p.129)」が1人現れる。その場にいるキャラクターをランダムに攻撃する",
  279. "最悪の事態。〔肉体点〕を0にして、そのキャラクターは行動不能に(致命傷表は使用しない)"
  280. ]
  281. ),
  282. "FatalT" => DiceTable::Table.new(
  283. "致命傷表",
  284. "2D6",
  285. [
  286. "死亡。",
  287. "死亡。",
  288. "昏睡して行動不能。1D6ラウンド以内に治療し、〔肉体点〕を1以上にしないと死亡。",
  289. "昏睡して行動不能。1D6ターン以内に治療し、〔肉体点〕を1以上にしないと死亡。",
  290. "大怪我で行動不能。体の部位のどこかを欠損してしまう。任意の〔能力値〕1つが1点減少。",
  291. "大怪我で行動不能。1D6ターン以内に治療し、〔肉体点〕を1以上にしないと体の部位のどこかを欠損してしまう。任意の〔能力値〕1つが1点減少。",
  292. "気絶して行動不能。〔肉体点〕の回復には治療が必要。",
  293. "気絶して行動不能。1ターン後、〔肉体点〕が1になる。",
  294. "気絶して行動不能。1D6ラウンド後、〔肉体点〕が1になる。",
  295. "気絶して行動不能。1D6ラウンド後、〔肉体点〕が1D6回復する。",
  296. "奇跡的に無傷。さきほどのダメージを無効に。"
  297. ]
  298. ),
  299. "AccidentT" => DiceTable::Table.new(
  300. "アクシデント表",
  301. "2D6",
  302. [
  303. "ゴミか何かが降ってきて、視界を塞ぐ。以降のケチャップに関する判定に修正が+1つく。あなたが追う側なら逃げる側のコマを2マス進める(逃げる側なら自分を2マス戻す)",
  304. "対向車線の車(もしくは他の船、飛行機)に激突しそうになる。運転手は難易度9の〔精神〕の判定を行うこと。失敗したら、乗物と乗組員全員は3D6のダメージを受けた上に、ケチャップから脱落",
  305. "ヤバイ、ガソリンがもうない! 後3ラウンド以内にケリをつけないと逃げられ(追いつかれ)ちまう",
  306. "露店や消火栓につっこむ。その乗物に1D6ダメージ",
  307. "一瞬ひやりと緊張が走る。〔精神点〕を2点減らす",
  308. "何かの障害物に衝突する。運転手は難易度7の〔精神〕の判定を行うこと。失敗したら、乗物と乗組員全員は2D6ダメージを受けた上に、ケチャップから脱落。成功しても、あなたが追う側なら逃げる側のコマを1マス進める(逃げる側なら自分を1マス戻す)",
  309. "走ってる途中に〔趣味〕に関する何かが目に映る。性業値判定を行うこと。「激」になると思わず見とれてしまう。あなたが追う側なら逃げる側のコマを1マス進める(逃げる側なら自分を1マス戻す)",
  310. "軽い故障が起きちまった。以降のケチャップに関する行為判定に修正が+1つく",
  311. "うっかり落し物。〔通常装備〕欄からアイテムを1個選んで消す",
  312. "あやうく人にぶつかりそうになる。運転手は難易度9の〔精神〕の判定を行う。失敗したら、その一般人を殺してしまう。あなたが追う側なら逃げる側のコマを1マス進める(逃げる側なら自分を1マス戻す)",
  313. "信号を無視しちまったら後ろで事故が起きた。警察のサイレンが鳴り響いてくる。DDはケチャップの最後尾に警察の乗物を加えろ。データは「制服警官(p.129)」のものを使用"
  314. ]
  315. ),
  316. "AfterT" => DiceTable::Table.new(
  317. "その後表",
  318. "2D6",
  319. [
  320. "ここらが潮時かもしれない。2D6を振り、その目が自分の修得している代償未満であれば、そのキャラクターは引退し、二度と使用できない",
  321. "苦労の数だけ喜びもある。2D6を振り、自分の代償の数以下の目を出した場合、経験点が追加で1点もらえる",
  322. "妙な恨みを買ってしまった。【仇敵】(p.95)を修得する。誰が【仇敵】になるかは、DDが今回登場したNPCの中から1人を選ぶ",
  323. "大物の覚えがめでたい。今回のセッションに登場した盟約へ入るための条件を満たしていれば、その盟約に経験点の消費なしで入ることができる",
  324. "思わず意気投合。今回登場したNPC1人を選び、そのキャラクターとの【コネ】(p.95)を修得する",
  325. "今回の事件で様々な教訓を得る。自分の修得しているアドバンスドカルマの中から、汎用以外のものを好きなだけ選ぶ。そのカルマの異能と代償を、別な異能と代償に変更することができる",
  326. "深まるチームの絆。今回のセッションでミッションが成功していた場合、【絆】(p.95)を修得する",
  327. "色々な運命を感じる。今回のセッションでトリコができていた場合、経験点の消費なしにそのトリコを常備化することができる。また、自分が誰かのトリコになっていた場合、その人物への【トリコ】(p.95)の代償を得る",
  328. "やっぱり亜侠も楽じゃないかも。今回のセッションで何かツラい目にあっていた場合、【日常】(p.95)を取得する",
  329. "くそっ! ここから出せ!! 今回のセッションで逮捕されていたら、【前科】(p.95)の代償を得る",
  330. "〔性業値〕が1以下、もしくは13以上だった場合、そのキャラクターは大阪の闇に消える。そのキャラクターは引退し、二度と使用できない"
  331. ]
  332. ),
  333. "KusaiMT" => DiceTable::Table.new(
  334. "臭い飯表",
  335. "2D6",
  336. [
  337. "やあ署長、ご苦労さん。いつでも好きなときに留置所を出ることができる。",
  338. "軽い取り調べを受ける。次の1ターンが終了するまで、未行動にならない。",
  339. "荒っぽい取り調べを受ける。次の1ターンが終了するまで、未行動にならない。1ターン休み。1D6ダメージを受ける(セーブ不可)。",
  340. "一晩泊まっていきなさい。次の日の朝まで未行動にならない。",
  341. "粘り強い取り調べが続く。1D6日後の朝まで未行動にならない。",
  342. "留置所のトイレで陵辱を受ける。1D6日後の朝まで未行動にならない。トラウマを1点受ける。",
  343. "劣悪な環境のせいで伝染病にかかる。1D6日後の朝まで未行動にならない。【病弱】の代償を得る。",
  344. "精神異常を訴え、無罪に。しかし、アーカム・アサイレムに移送され、1D6回別のキャラクターでセッションを行うまで、そのキャラクターを使用できない。キジルシの代償の中から、ランダムに1つの代償を得る。",
  345. "起訴されて有罪に。海上刑務所行き。1D6回別のキャラクターでセッションを行うまで、そのキャラクターを使用できない。【前科】の代償を得る。",
  346. "起訴されて有罪に。海上刑務所行き。2D6回別のキャラクターでセッションを行うまで、そのキャラクターを使用できない。【前科】の代償を得る。",
  347. "起訴されて有罪に。海上刑務所行き。終身刑。そのキャラクターは引退する。"
  348. ]
  349. ),
  350. "EnterT" => DiceTable::Table.new(
  351. "登場表",
  352. "2D6",
  353. [
  354. "「こっから先にはいかせないぜ」 【仇敵】がいれば現われ、血戦が始まる。現在の血戦、もしくはケチャップが終了したら、処理を行うこと。",
  355. "「待たせたな、みんな!」 ジオラマの好きな場所に自分のキャラクターを配置する。",
  356. "おっと、鉢合わせ。ランダムにジオラマ上の敵を1体選ぶ。選んだ敵と同じマスに、そのキャラクターを配置する。",
  357. "全力ダッシュで駆けつける! 〔肉体点〕を1D6点消費すれば、ジオラマの好きな場所に自分のキャラクターを配置する。そうでなければ、登場できない。",
  358. "裏道を歩いていたら、偶然その場所にでくわした。DDはジオラマの好きな場所にそのキャラクターを配置する。",
  359. "「キキィー!」 もしもそのキャラクターが乗物を装備していれば、DDはジオラマの好きな場所にそのキャラクターを配置する。そうでなければ、登場できない。",
  360. "……間に合ったみたいだな。仲間を1人選び、そのキャラクターと同じマスに自分のキャラクターを配置する。",
  361. "ラッキー、「ジャリ銭」を拾った。……と、そんな場合じゃないよな。",
  362. "をっと、お前の好物だ。〔性業値〕判定を行え。「律」ならもう一回、登場表を振ることができる。それ以外なら、キャラクターを配置できない。",
  363. "んー。ここは一度通ったような。疲労から〔精神点〕を2点減少。",
  364. "くあー。完全に道に迷っちまった。この実行フェイズには登場できない。"
  365. ]
  366. ),
  367. "BudTT" => DiceTable::Table.new(
  368. "バッドトリップ表",
  369. "2D6",
  370. [
  371. "自分の身の周りにいる人たちが異様な何か(悪魔、宇宙人、ゾンビ、お前と同じ顔をした誰か…)に変貌し襲い掛かってくる。お前はNPCとなって、同じ場所にいる誰かに血戦をしかける。血戦が終了すれば(そして生きていれば)、視界は元に戻っている。",
  372. "世界は一つ。オープンソース。愛で結びつくべきなんだ。お前は自分の知っていることをペラペラと話だし、1D6ターンの間、聞かれれば知っていることを何でも話してしまう。",
  373. "自分と他人の区別がつかなくなり、現実感が薄れる。〔精神点〕を1D6点減少する。",
  374. "誰かが自分を殺そうと企んでいるような錯覚を覚える。1D6ターンの間、ペテン師の代償【疑心暗鬼】を修得する。",
  375. "風景が極彩色に彩られる!もっと……もっと極彩色に!もし他にも「麻薬」カテゴリのアイテムを持っていれば、その中の1個を使用する(行動は使わない)。",
  376. "目の前にいる人物が非常にいとおしく思えてくる。同じ場所にいるキャラクターの中からランダムに1人選ぶ。1D6ターンの間、そのキャラクターのトリコになる。",
  377. "魅力的な裸の異性が、あなたの目の前で誘惑する幻覚を見る。〔性業値〕判定を行う。「激」になると服を脱ぎだす。もしも外にいればそのエリアの〔治安〕の難易度の〔犯罪〕判定を行う。失敗すると「臭い飯」表を振る。",
  378. "お前は痛みを感じなくなる。1D6ターンの間、〔肉体点〕の重症のペナルティが無効化される。",
  379. "自分の持っているものから触手が生え、あなたにからみつく。自分の〔通常装備〕欄のアイテムの中からランダムに1種を選ぶ。それを捨てる。",
  380. "皮膚の中を無数の蟲が蠢いているのを感じる。〔肉体点〕を3点減少する。",
  381. "神々しい声が聞こえてくる。1D6ターンの間、自分の好きな能力値を1点上昇することができる。"
  382. ]
  383. ),
  384. "GetgT" => DiceTable::Table.new(
  385. "報酬・ガラクタ表",
  386. "2D6",
  387. [
  388. "持ち主の〔生活〕と等しい個数の《食事》(基本80p、小道具・日用品)",
  389. "持ち主の〔生活〕と等しい個数の《トルエン》(基本79p、小道具・麻薬)",
  390. "持ち主の〔生活〕と等しい個数の《ジャリ銭》(基本78p、小道具・お金)",
  391. "壊れた実用品。実用品表で決定。(壊れたアイテムは、1ターン使用し〔教養〕で難易度9の判定に使用すると直せる)",
  392. "《テレカ》(基本78p、小道具・通信手段)",
  393. "何もなかった(涙)。残念でした。",
  394. "《ロープ》(基本78p、小道具・保安器具)",
  395. "《トヨトミピストル》(基本74p、武器)",
  396. "《自転車》(基本76p、乗物)",
  397. "《ふとん》(基本79p、小道具・日用品)",
  398. "持ち主の〔趣味〕からランダムに1種類選ぶ。その趣味おたからを1個ランダムに選ぶ。"
  399. ]
  400. ),
  401. "GetzT" => DiceTable::Table.new(
  402. "報酬・実用品表",
  403. "2D6",
  404. [
  405. "持ち主と同じタイプの汎用おたから(基本82p、汎用おたから)",
  406. "価格5の《ホテル》の使用券(基本80p、小道具・サービス)",
  407. "《苦力》(基本80p、小道具・手下)",
  408. "《カメラ》(基本80p、小道具・手下)",
  409. "持ち主が使っていた装備(ただし、一般アイテムに存在しない装備をPCは使用できない)",
  410. "持ち主の〔生活〕と等しい個数の《札巻》(基本78p、小道具・お金)",
  411. "持ち主の〔生活〕と等しい個数の《大麻》(基本79p、小道具・麻薬)",
  412. "《ノートパソコン》と《携帯電話》(基本78p、79p、小道具・日用品、通信手段)",
  413. "《ヴェスパ》(基本76p、乗物)",
  414. "《救急箱》(基本79p、小道具・保安器具)",
  415. "《札束》(基本78p、小道具・お金)"
  416. ]
  417. ),
  418. "GetnT" => DiceTable::Table.new(
  419. "報酬・値打ち物表",
  420. "2D6",
  421. [
  422. "社会的身分。【日常】の異能を手に入れる。",
  423. "《人柱》(基本184p、盟約おたから・沙京流氓)",
  424. "貴重な貴金属。1ターン使って〔生活〕で難易度9の判定に成功すれば《トランク》と交換できる。",
  425. "持ち主と同じタイプの汎用おたから(基本82p、汎用おたから)",
  426. "持ち主の〔生活〕と等しい個数の《ヘロイン》(基本79p、小道具・麻薬)",
  427. "持ち主の〔生活〕と等しい個数の《札束》(基本78p、小道具・お金)",
  428. "持ち主の〔生活〕と等しい個数の価格5以下の武器(基本79p、小道具・麻薬)",
  429. "《ロールスロイス》(基本76p、乗物)",
  430. "持ち主の〔趣味〕からランダムに1種類選ぶ。その趣味おたからを1個ランダムに選ぶ。",
  431. "《トランク》(基本78p、小道具・お金)",
  432. "《宝箱》(基本78p、小道具・お金)"
  433. ]
  434. ),
  435. "GetkT" => DiceTable::Table.new(
  436. "報酬・奇天烈表",
  437. "2D6",
  438. [
  439. "好きな盟約おたから1個(プレイヤー全員で相談して決定)",
  440. "《気球》(基本76p、乗物)",
  441. "《チェインソー》(基本74p、武器)",
  442. "誰かから感謝される。それだけ?",
  443. "持ち主の〔趣味〕からランダムに1種類選ぶ。その趣味おたからを1個ランダムに選ぶ。",
  444. "何もなかった(涙)。残念でした。",
  445. "持ち主と同じタイプの汎用おたから(基本82p、汎用おたから)",
  446. "《フォークリフト》(基本76p、乗物)",
  447. "《RPG-7》(基本74p、武器)",
  448. "倒されたキャラクターは、致命傷表を振り、まだ生きていれば、そのキャラクターを倒した者のトリコになる。",
  449. "「先にイッてるぜ」そのキャラクター1体を倒した者に経験点が1点与えられる。"
  450. ]
  451. ),
  452. "PayT" => DiceTable::Table.new(
  453. "落とし前表",
  454. "2D6",
  455. [
  456. "闇のゲーム。ロシアンルーレットや地下闘技場への出場といった、致死率の高い理不尽な労働に従事させられる。この落とし前を1回受けるたびに、1D6を振る。1の出目が出ると、そのキャラクターは死亡する。",
  457. "拷問。心身ともに痛めつけられる。この落とし前を1回受けるたびに、【悪夢】、【疑心暗鬼】、【出不精】、【依存体質】、【弱虫】、【虚弱】の中から代償を一つ選んで修得する。どの代償もすでに修得していた場合、そのキャラクターは死亡する。新しい恋人ができるたび、この落とし前の効果を1回分、無効化することができる。",
  458. "苦役。売春や、組織犯罪の資金源になるよう強制労働に従事させられる。この落とし前を1回受けるたびに、以降、セッションの間に「苦役」という特に何の効果ももたらさない計画的行動を一度行わなければいけなくなる。セッション中に規定の「苦役」の回数をこなすことができなかったキャラクターは、「苦役」の必要回数に満たない数だけ、「落とし前表」を使用しなければならない。《トランク》を1個消費すると、この落とし前表の効果を1回分、無効化することができる。",
  459. "係累への被害。自分の身内や恋人が殺される。この落とし前を1回受けるたびに、トラウマを1点受ける。",
  460. "部位破壊。指や手首を切り落とされたり、臓器を摘出されたりする。この落とし前を1回受けるたびに、「致命傷表」の6番の効果を受ける。",
  461. "罰金。法外な違約金を払わされたり、借金を負わされたりする。この落とし前を1回受けるたびに、〔サイフ〕の最大値が1点減少する。〔サイフ〕の最大値が0点になると、そのキャラクターは死亡する。《札束》を5個消費すると、この落とし前の効果を一回分、無効化することができる。",
  462. "さらし者。謝罪会見を行わされたり、恥ずかしい動画や写真を公開されたりする。この落とし前を1回受けるたびに、【世界の敵】、【悪名】、【有名人】、【狼少年】、【手配書】、【カモ】の中から代償を一つ選んで修得する。どの代償もすでに修得していた場合、そのキャラクターは死亡する。経験点を2点消費すると、この落とし前の効果を1回分、無効化することができる。",
  463. "刻印。坊主頭にされたり、恥ずかしい入れ墨や刻印を刻み付けられたりする。この落とし前を1回受けるたびに、そのキャラクターが行うロマンスや交渉の判定の難易度が1点上昇する。",
  464. "差し押さえ。この落とし前を1回受けるたびに、そのキャラクターは、自分が装備しているもっとも価格の高いアイテム1つを失う。おたからは価格8として扱い、もっとも高い価格のアイテムを複数持っている場合は、その中からランダムに選ぶ。",
  465. "監禁。マグロ漁船や地下工場に閉じ込められ、長期的な労働に従事させられる。この落とし前を1回受けるたびに、一回別のキャラクターでセッションを行うまで、そのキャラクターを使用できない。《札束》を5個消費すると、この落とし前の効果を1回分、無効化することができる。",
  466. "去勢。性的な機能を破壊される。この落とし前を受けると、「無言で押し倒す」ことができなくなる。この落とし前を二回以上受けると、そのキャラクターは死亡する。"
  467. ]
  468. ),
  469. "MinamiRET" => DiceTable::Table.new(
  470. "ミナミ遭遇表",
  471. "2D6",
  472. [
  473. "(場所)大変だ、阪神が勝った。4000人のトラキチが、一緒に道頓堀に飛び込もうと迫る。飛び込むなら水中には「下水ワニ」(基本132p)が待っている。拒否するならトラキチたちは「ベンガル虎」(基本133p)を亜侠にけしかける。",
  474. "(場所)突然の夕立、そして稲妻! 武器を一番多く持っている亜侠に雷が落ちる。複数いた場合、1D6で一番高い目を出した亜侠に落ちる。黒焦げになり、パーマがかかり、ランダムに一つ武器を失う(熔ける)。",
  475. "(一人)酔っ払いの吐瀉物を浴びて〔精神点〕に1ダメージ。風呂に入って着替えるまで、あらゆる交渉は自動的に成功度が-1される。",
  476. "(一人)好みの恋愛対象に出会ったと思ったら「美人局」(基本124p)だった!",
  477. "(一人)うっかり入った店が暴力喫茶だった! 「押し売り」(基本124p)相当。",
  478. "(一人)しつこいキャッチに絡まれる。「勧誘員」(基本124p)相当。",
  479. "(一人)裏路地で襲われる。「痴漢・痴女」(基本124p)相当。",
  480. "(一人)道を渡ろうとしたら路面電車に撥ねられる。〔肉体点〕に1D6ダメージ。",
  481. "(一人)契約刑事に恐喝される。逮捕されたくなければ、〔サイフ〕を1減らせ。",
  482. "(一人)うっかりマリア・ヴィスコンティを怒らせた! この場では何も起こらないが、マリアは忘れない。次に亜侠が致命傷表送りになったとき、マリアが出現して亜侠の利き腕を吹き飛ばして去る(致命傷表の判定が必ず「7~9」になる)。",
  483. "(一人)「円盤」(基本138p)に襲われ、さらわれる。1ターン経って戻ってくると、頭からアンテナが生えている。キャラクターイラストにアンテナを書き加えろ。それが嫌なら戦うこと。"
  484. ]
  485. ),
  486. "ChinatownRET" => DiceTable::Table.new(
  487. "中華街遭遇表",
  488. "2D6",
  489. [
  490. "(一人)好みの恋愛対象に襲われて目くるめく一時を過ごす。だが1ターン経って目が覚めると、房中術で性転換させられている。",
  491. "(場所)人を食う「パンダ」(基本133p)に襲われる。",
  492. "(一人)道端の占い師をうっかり撥ねて、人肉饅頭の呪いを受ける。このセッション中に行動不能になったら、狂気の料理人に饅頭にされて食われ、後には何も残らない。",
  493. "(場所)漢方薬局を冷やかしていたら、世界自然保護プロレス基金WWWWF(World_Wide_Wildelife_Wrestling_Found)のレスラー1D6人(「街頭覇王」(基本134p))に襲われる。亜侠が手に取った犀の角が気に入らなかったのだ。誰かが〔サイフ〕を1支払ってTシャツを買うと許してくれる(キャラクターイラストにパンダのマークをつけること)が、そうでなければ戦うしかない。",
  494. "(場所)化石を売りつけようとする「押し売り」(基本124p)に遭遇。品物は1D6を振って決める。1:ゴモラの全身骨格、2:マチカネワニの涙、3:明石原人の糞石、4:生きた北京原人、5:豊臣秀吉15歳のしゃれこうべ、6:三葉虫ボトルキャップ",
  495. "(場所)映画の撮影現場に紛れ込んでしまった! このセッションの間、戦闘時になると敵味方全員に《透明ワイヤー》の効果がつく。既に持っていた場合、「跳ぶ」を選んでも使用回数を消費しない。",
  496. "(一人)美味しい中華料理を食いすぎて、一時的にすごく太る。このセッションの間は、〔肉体〕が+1されるが、その亜侠に対する命中判定にも+1の修正がつく。",
  497. "(一人)道端で碁の勝負を見ていたら、いつのまにか1ターン経っていた。代わりに〔精神点〕が1回復する。",
  498. "(一人)お前をスターと間違えたおっかけの大群が迫ってくる。このセッションの間、【有名人】の代償がつく。",
  499. "(場所)空飛ぶギロチンを持った老人と片腕の格闘家が戦っている。二人はどちらもチームに加勢を求める。老人は「罪狩」(基本135p)、格闘家は「殺人鬼」(基本137p)だ。味方するなら、どちらに手を貸すか決めて戦闘を行え(味方された本人は戦わない)。どちらかを倒したらもう一人は礼を言って即座に去る。倒したのが格闘家なら《不肖の弟子》が、老人なら《空飛ぶギロチン》(本格的武器)が手に入る。",
  500. "(場所)「狂人」とその一党が現れた! キャラクターシートの「好きな映画」が空欄だった亜侠は、頭に火をつけられる。キャラクターのイラストから髪を取り除け。シートに顔を描いていなかった場合、キャラクターシートを燃やすか、自分の頭を燃やすか、〔肉体点〕を1減らすこと。「狂人」を倒すことはできない。彼は永遠だ。"
  501. ]
  502. ),
  503. "WarshipLandRET" => DiceTable::Table.new(
  504. "軍艦島遭遇表",
  505. "2D6",
  506. [
  507. "(場所)蟹の押し売りに遭う。しかもただの押し売りではない、食い詰めた「超人兵士」(基本134p)だ! 蟹(価格3の「食事」(基本79p))を買うか、そうでなければ戦うこと。",
  508. "(場所)救世軍の配給に長い行列ができている。〔性業値〕判定で「激」を出した亜侠はつい並んでしまい、1ターン消費して「食事」(基本79p)をゲット。",
  509. "(場所)荒廃した通りを横断していたら撃たれる。スナイパーだ! 全員1D6を振り、一番低い目を出した亜侠は〔肉体点〕に1D6のダメージ。",
  510. "(場所)突然の路面陥没! 乗り物を所持している亜侠は〔精神〕9の判定に成功しないと、逃げ遅れて乗り物に2D6のダメージを受ける。",
  511. "(場所)季節はずれの雪が降っている。青く光ってなんだかとても美しい。とりあえず〔肉体点〕と〔精神点〕に1ダメージ。",
  512. "(場所)飢えた野犬がぞろぞろついてくる。このセッション中に軍艦島で行動不能になった亜侠は、すぐに食われて後には何も残らない。",
  513. "(一人)気がつくと食玩塗りの搾取工場の中……。コンビナートの手配師に捕まったのだ。脱出するのに1ターン無駄にするが、見張りの「ブラックアドレス」(基本127p)一体と戦って勝てば時間を無駄にせずにすむ。",
  514. "(一人)自宅が膨張する203高地に取り込まれた。脱出するのに1ターンかかる上、アジトの場所が「軍艦島」になってしまう。",
  515. "(場所)ガス爆発!1D6して出た目のエリアに飛ばされる上、飛ばされたエリアの遭遇表を振らねばならない。1:ミナミ、2:十三、3:沙京、4:中華街、5:官庁街、6:軍艦島",
  516. "(場所)ひょろひょろ跳んできた「ミサイル」(基本130p)と目が合った。目標を見失っていたミサイルは、亜侠を新たな目標に決めて親しげに近づいてくる。",
  517. "(一人)「タイラー・ダーデン」に遭遇し、啓蒙される。これがお前の人生だ。お前はいつか必ず死ぬ。それを認識しない限り、お前は糞のままだ。〔肉体点〕と〔精神点〕に1ダメージ。〔性業値〕が2下がる。更にこのセッション中は「迷」が出ても「激」として扱う。"
  518. ]
  519. ),
  520. "CivicCenterRET" => DiceTable::Table.new(
  521. "官庁街遭遇表",
  522. "2D6",
  523. [
  524. "(場所)大規模なデモにぶつかって身動きが取れなくなった。まずいと思う間もなく、列強の鎮圧部隊が容赦なく群集に向かって発砲する。阿鼻叫喚の中で全員〔肉体点〕に1D6のダメージ。",
  525. "(場所)火事だ! ビルがぼうぼう燃えている。〔犯罪〕8の判定に失敗すると、野次馬の中でスリにやられ、アイテムをランダムに一つ失う。",
  526. "(場所)株価暴落で取り付け騒ぎが起こっている。〔生活〕4以上の亜侠は〔サイフ〕が1減る。",
  527. "(一人)身投げか事故か突き落とされたのか、ビルから人が振ってきた。〔戦闘〕で難易度9の判定に成功しないと、直撃されて〔肉体点〕に2D6のダメージ。",
  528. "(場所)観光客に写真を撮られる。このセッション中、亜侠に対する逮捕判定の難易度は-1される。",
  529. "(一人)汚職警官に職務質問される。「押し売り」(基本124p)相当。",
  530. "(場所)軍事パレードが開催中だ。「デモ行進」(基本124p)相当。",
  531. "(場所)今日は即売会だ。「ヲタク」か「マニア」の〔趣味〕を持つ亜侠は、1ターン消費して買い物しないと、〔精神点〕に1D6ダメージ。",
  532. "(一人)爆弾テロだ! 1D6して出た目のエリアに飛ばされる上、飛ばされたエリアの遭遇表を振らねばならない。1:ミナミ、2:十三、3:沙京、4:中華街、5:官庁街、6:軍艦島",
  533. "(場所)ビルから降ってきたお札をみんなが奪い合っている。争奪戦に加わるなら、〔肉体点〕に1D6ダメージを受けて〔サイフ〕を1回復してよい。",
  534. "(一人)閉鎖されているはずの地下鉄の入り口が開いている……。性業値判定で「激」が出るとふらふらと入ってしまい、1ターン経った後戻る。奇天烈の宝物表(基本140p)を1回振れる。トラウマを1点受け、中で起こったことは何も憶えていない。入り口は固く閉ざされ、もう開かない。……今のところは。"
  535. ]
  536. ),
  537. "DowntownRET" => DiceTable::Table.new(
  538. "十三遭遇表",
  539. "2D6",
  540. [
  541. "(場所)地震だ! 亜侠自身には被害はないが、家が大変なことに。帰宅すると、アジト装備がランダムに1個壊れている。アジト装備がなかった場合、家が壊れている。",
  542. "(場所)山から下りてきた猪が突っ込んでくる! データは「トラック野郎」(基本123p)を使う。",
  543. "(一人)草野球の代打を頼まれる。1D6せよ。「スポーツ」の趣味があれば+1。1,2:三振! 冷たい視線を浴びて〔精神点〕-1、3,4:ヒット! 喝采を浴びて〔精神点〕1回復。5,6:ホームラン! そしてガラスの割れる音!窓を割られた家から怒り狂った「おかん」(基本122p)が飛び出して、大根片手に亜侠を襲う。",
  544. "(場所)「獅子舞」(基本128p)が亜侠の周りをぐるぐる周って離れようとしない。この状態で戦闘が起こると、獅子舞は敵に加わって亜侠を襲う。〔サイフ〕を1渡せば、獅子舞は歯をがちがち言わせて去る。",
  545. "(一人)地獄湯の「勝負師」(基本126p)に賭けを挑まれ、ざわざわする。",
  546. "(一人)お魚くわえようとするドラ猫に襲われる。〔犯罪〕で難易度9の判定に失敗したらランダムにアイテム一つを失う。亜侠が「食事」(基本79p)を持っていれば、優先的にそれを狙う。",
  547. "(場所)神風師団の自警団に囲まれた! 名前にカタカナがある亜侠がいたら集中的に襲われる(「忘八」(基本128p)1D6人相当)。日本人名の亜侠しかいなければ、被害を受けることはない。",
  548. "(一人)生臭坊主/生臭尼僧にお布施を要求される。データは「勧誘員」(基本124p)。",
  549. "(一人)大仏から身投げをした人が降ってきた。〔戦闘〕で難易度9の判定に成功しないと、直撃されて〔肉体点〕に2D6のダメージ",
  550. "(場所)祭囃子が聞こえてきたかと思ったら、目の前をすごい早さで神輿が通り過ぎる。性業値判定で「激」が出た亜侠は、思わず祭に参加してしまい、高速神輿に連れ去られる。1ターン戻ってこない上、疲れきって〔肉体点〕-1。",
  551. "(一人)好みの恋愛対象に誘われて夢のような時間を過ごし、気が付くと肥溜めに肩まで漬かっていることに気付く。おばけに化かされた!1ターン消費する。風呂に入って着替えるまで、あらゆる交渉は自動的に成功度が-1される。この効果は一緒に行動する仲間の判定にも影響する。"
  552. ]
  553. ),
  554. "ShaokinRET" => DiceTable::Table.new(
  555. "沙京遭遇表",
  556. "2D6",
  557. [
  558. "(一人)いつのまにか、少女/少年が1人ついてきている。奴隷のようだが、亜侠を主人だと思っているらしく離れようとしない。何に相当するか1D6を振れ。1:【守るべき者】(基本103p)、2:愛人(基本80p)、3:使用人(基本80p)、4:居候(基本80p)、5:落とし穴(基本78p)、6:食事(基本79p)。性別はプレイヤーが決めてよい。",
  559. "(場所)どこからか煙が漂ってくる……麻薬工場が火事だ! 煙を吸って目を回し、各自1D6を振れ、出た目のドラックの効果を受ける。直接摂取ではないので、ドラッグの強度からは-3。1:コカイン、2:大麻、3:ハルシオン、4:トルエン、5:エクスタシー、6自白剤(ドラッグのデータ→基本79p)",
  560. "(場所)やけに人懐っこい豚がいると思ったら、人の味を覚えた豚だった! 戦闘になる。データは「ベンガル虎」(基本133p)を使う。",
  561. "(場所)あばれ象が車を踏み潰して暴走している! 乗り物を所持している亜侠は〔精神〕9の判定に成功しないと、逃げ遅れて乗り物に2D6のダメージを受ける。",
  562. "(場所)インド人が死んでいる……。死体を漁るなら1D6。1:カレー味の《視肉》(基本85p)、2:サファイア(札束(基本78p)相当)、3:《あわてるなタオル》(基本93p)、4:RPG-7(基本74p)、5:死体じゃなくて「ゾンビ」(137p)だった、6:「はきだめの悪魔」だった",
  563. "(一人)バクシーシ! バクシーシ! じゃりンこ10人が〔サイフ〕1点払うまでぞろぞろついてくる。何かあると「邪魔」(基本37p)10人分を行う。",
  564. "(一人)いきなり足に何かが噛み付く。「下水ワニ」(基本132p)だ! 〔肉体〕9の判定に成功すると振りほどけるが、失敗すると〔肉体点〕に1ダメージ。成功するまで判定すること。〔肉体点〕が0になると、亜侠は水路に引きずり込まれて食われる。",
  565. "(一人)気がつくと奴隷船の船倉の中……。奴隷商人の人狩りに捕まったのだ。脱出するのに1ターン無駄にするが、見張りの「ククバット」(基本127p)1体と戦って勝てば時間を無駄にせずにすむ。",
  566. "(一人)アラブの露天商に水煙草を勧められる。一服してまったりする亜侠だが、その懐に小猿が手を伸ばす……。アイテムをランダムに1つ失う。",
  567. "(一人)魚を満載したトラックから鮫が落ちてきて、亜侠に噛み付いて死ぬ。怪我はないが離れようとしない。死んだ鮫をぶら下げて歩くことになるので、セッション終了時まで、その亜侠と一緒にいると治安が+2される。",
  568. "(場所)祝祭だ! 巨大なジャガーノート(山車)が通りを突き進んでくる。これに轢かれると幸せな来世が保証されるのだ。性業値判定を3回振れ。全部「激」を出した亜侠は、思わず車輪の下に飛び込んで〔肉体点〕に10のダメージを受ける。この亜侠が死んだら、次に作るキャラクターに異能と代償を一つずつ受け継がせること。これがカルマだ。"
  569. ]
  570. ),
  571. "LoveLoveRET" => DiceTable::Table.new(
  572. "らぶらぶ遭遇表",
  573. "2D6",
  574. [
  575. "(場所)お互いに運命を感じる。この後のロマンス判定で成功して、トリコを獲得した場合、セッション終了時にそのトリコを経験点消費なしに常備化できる。ただし、このトリコと別れたり、このトリコが死亡したりすると、経験点が1点減少する。",
  576. "(場所)「……こんなとこで何やってんの?」「げ」もし、自分のトリコの中に、この場所と同じ〔趣味〕の持ち主がいた場合、その人物が現れる。血戦を行うこと。",
  577. "(一人)デート中に相手の姿を見失ってしまう。〔犯罪〕で難易度9の判定を行う。成功すると、その場所の〔趣味〕に対応した趣味おたからをランダムに1つ獲得する。失敗すると、ロマンス判定は行えなくなる。",
  578. "(一人)楽しくショッピング! 〔生活〕で難易度9の判定を行う。成功すると、その成功度と同じ値だけ、〔精神点〕を回復できる。失敗すると、セッション中、この後のロマンス判定のファンブル率が2点上昇する。",
  579. "(一人)「…………」互いに遠慮して気まずい感じ。〔恋愛〕で難易度9の判定を行う。成功すると、この後のロマンス判定の難易度が1点減少する。失敗すると、この後のロマンス判定の難易度が2点上昇する。",
  580. "(場所)亜侠稼業を忘れてしまいそうなほど、充実した時間を過ごす。デートを行っているキャラクター全員は、〔精神点〕が2点回復する。",
  581. "(一人)「うーん、ここつまんないね。場所変えよっか」〔恋愛〕で難易度9の判定を行う。成功すると、この後のロマンス判定の難易度が1点減少する。失敗すると、デート参加者全員は、このエリアの遭遇表をさらに1回ずつ振らなければならない。",
  582. "(一人)趣味の会話で盛り上がる! 〔教養〕で難易度9の判定を行う。成功すると、それ以降一度だけ、そのセッション中に行う判定の難易度を、その成功度と同じ値だけ減少することができる。失敗すると、セッション中、この場所の〔趣味〕が未修得の状態になる。",
  583. "(一人)「あぶない、暴れ馬だッ!」〔戦闘〕で難易度9の判定を行う。成功すると、デートの相手の好みを、自分のタイプと同じものに変更することができる。失敗すると、デートの相手は1D6点のダメージを受ける(セーブ不可)。",
  584. "(場所)「ようよう、綺麗なねぇちゃん、連れとるやんけ」「三下」が1D6人現れる。血戦を行うこと。",
  585. "(場所)「んー付き合っちゃおうか」デートに参加したキャラクターは、この後のロマンス判定が自動的に成功する。"
  586. ]
  587. ),
  588. "AjitoRET" => DiceTable::Table.new(
  589. "アジト遭遇表",
  590. "2D6",
  591. [
  592. "(一人)「強盗殺人の容疑で逮捕する! お前には黙秘権があり、供述は、法廷で不利な証拠として……」どやどやと踏み込んでくる警官たち。「制服警官」がお前を対象にして【逮捕】の異能を使ってくる。「制服警官」の判定が失敗すると、それ以降、このセッション中では、「臭い飯」表を振るとき、その2D6の目からマイナス3することができる。",
  593. "(一人)ピンポーン♪ チャイムの音。イヤな予感がするなぁ。1D6を振る。奇数なら「勧誘員」が【ムダ話】を、偶数なら「押し売り」が【売り口上】を使ってくる。",
  594. "(一人)イメージチェンジ! たまにはスタイルを変えてみようかな? 外見表を使って、ランダムに外見を変える。そのセッション中、各エリアで〔犯罪〕の行為判定を行うとき、そのエリアの衣装欄に書かれた外見であれば、振ることのできる2D6の回数が1回上昇する。",
  595. "(場所)「やっぱり、ここにいやがったな」このアジトにいるキャラクターが【コネ】か【仇敵】か【トリコ】の汎用異能、もしくは汎用代償を修得していれば、それに対応するキャラクター(コネ、仇敵、自分の主人)が現れる。コネなら、アジトにいる全員は、価格がそのキャラクターの〔生活〕-1以下のアイテムを1つ獲得できる。仇敵なら、アジトにいる全員は1ダメージを受ける(セーブ不可)。自分の主人なら【トリコ】の持ち主は、別れをつげられ【トリコ】を失うが〔精神点〕が2D6点減少する。",
  596. "(一人)「よう、元気にしてるか?」家族や友人からの突然の連絡。懐かしい気持ちに高揚しつつも、優しい気持ちになる。〔性業値〕を1点上昇、もしくは1点減少することができる。",
  597. "(場所)何となくテレビでもつけ、面白いチャンネルがないか、探してみる。うーん。ケーブルテレビに入るべきか……。アジトの持ち主の〔生活〕の値と同じ回数だけ「趣味決定表」を振り、各自、その結果と自分の〔趣味〕を比べてみる。自分が持っている〔趣味〕と同じ〔趣味〕が出ていれば、その回数だけ、自分の〔精神点〕を回復する。",
  598. "(一人)あ、こんなところに買い置きが。《食事》を1D6個獲得する。",
  599. "(場所)「みんなで鍋でもするか」現在、このアジトにいるキャラクターと手下カテゴリーのアイテムの合計数だけ、〔精神点〕が回復する。",
  600. "(一人)ふぅ。やっぱり、自宅が一番落ち着くなぁ。もしも修得していなければ【日常】の異能を修得する。",
  601. "(一人)一休み……のつもりが、ついつい居眠りしてしまう。アジトに自分しかいなければ、性業値判定を行うこと。「律」になれば、〔精神点〕をアジトの〔快適度〕の半分だけ回復することができる。「激」なら、「睡眠」をしてしまう。「迷」なら、次のターンもアジトから移動できず、行動もできない。アジトに誰かいたら、もう一度アジト遭遇表を振ること。",
  602. "(一人)謎の贈り物が届く……。趣味おたからの中からランダムに1つを選び、それを獲得する。その後、1D6を振る。その目が、このイベントで趣味おたからを獲得した回数以下だった場合、贈り主の呪いによって2D6点のダメージを受ける(セーブ不可)。"
  603. ]
  604. ),
  605. "JigokuSpaRET" => DiceTable::Table.new(
  606. "地獄湯遭遇表",
  607. "2D6",
  608. [
  609. "(一人)なぜかあなたはローマ時代にタイムスリップする! 今後、このシナリオのあらゆる判定の難易度が1減少する(累積不可)。",
  610. "(場所)お湯の中に鮫が! 〔戦闘〕で難易度9の判定を行う。失敗したキャラクターは〔肉体点〕を1D6点減少。",
  611. "(一人)地獄湯の出張販売! 望むなら価格のある地獄組の盟約アイテムを購入することができる。",
  612. "(場所)ふぅ。湯上がりは親でも惚れるね。〔恋愛〕で難易度9の判定に成功すると、その場にいる好きなキャラクター1人をトリコにすることができる。",
  613. "(一人)あああ、なんか面白そうだなぁ。性業値判定を行う。「激」ならついついギャンブルゾーンに行ってしまう。「迷」なら行動済みになってしまう。「ギャンブル」の〔趣味〕の持ち主は、サイコロの目に2を加えること。",
  614. "(場所)地獄組による監視。もしチームが彼らと敵対していれば、うまく身を隠す必要がある。〔犯罪〕で難易度9の判定を行う。失敗すると、〔肉体点〕を1点減少する。そうでなければ、何もなし。",
  615. "(一人)うーん。のぼせちゃったかな。〔精神点〕を1点減少する。",
  616. "(場所)道に迷いそうになる。〔教養〕で難易度9の判定を行い、失敗したキャラクターは、地獄湯内の6つのゾーンの中からランダムに1つを選び、そこに移動する。",
  617. "(一人)ナンパにあう。〔恋愛〕で難易度9の判定に成功すると、色々おごってもらえる。〔サイフ〕を1点回復することができる。",
  618. "(場所)まずい。お湯の温度が恐ろしいことになっている! 〔精神点〕を2点減少する。",
  619. "(一人)価格3の買い物を行うと、マッサージをしてもらえる。〔肉体点〕を1点、〔精神点〕を1D6点回復できる。"
  620. ]
  621. ),
  622. "JailHouseRET" => DiceTable::Table.new(
  623. "JAILHOUSE遭遇表",
  624. "2D6",
  625. [
  626. "「あちらのお客様からです」と渡されたグラス。その中には爆発寸前の《手榴弾》が入っていた。手榴弾はそのPCに命中したものとして扱う。",
  627. "「……パパぁ」小さな「じゃりンこ」があなたの裾をつかむ。そのセッションの間、「じゃりンこ」がついてきて、そのPCのロマンス判定を【邪魔】する。",
  628. "「あ、サイフがない!」〔サイフ〕を1点減らす。",
  629. "乗物が盗まれる! 装備の中に乗物があった場合、そのアイテムを失う。",
  630. "誰かと荷物を間違えてしまう! 自分の装備からランダムに1個のアイテムを失う。その後、自分の〔生活〕と等しい報酬表を振ってアイテムを1つ手に入れる。",
  631. "「な、なんだテメェ!」他の客たちの喧嘩に巻き込まれる。〔肉体点〕を2点減少(セーブ不可)。",
  632. "「突然だけど……別れましょう」あなたに恋人がいれば、そのキャラクターが現れ、2人は別れる。",
  633. "何かの間違いだろうか。きみのあおったグラスの中に、《エクスタシー》が混じっていた! か、体があつィっ!",
  634. "「ようチンピラ、まだ生きてたのかい?」契約刑事のマリアが絡んでくる。彼女を楽しませるために「飲み会」を行わないとチーム全員が「臭い飯」表を一回ずつ振らなければいけない。",
  635. "突然の銃声! 「侠客」1人がきみに向かって《トカレフ》を「仁義なく」ぶっ放す! 血戦を開始せよ。",
  636. "「エルヴィス」があらわれ、店で奇跡的なまでに楽しいパーティーが行われる。チーム全員が気付くと1日が経過していた。"
  637. ]
  638. ),
  639. "TreatmentIT" => DiceTable::Table.new(
  640. "治療イベント表",
  641. "2D6",
  642. [
  643. "不治の病だったことが分かる。1D6セッション後に死亡するが、今回以降のセッションで得られる経験値はすべて2倍になる。",
  644. "治療中の動物が脱走! サイコロを1個振り、1~4なら「番犬」が、5~6なら「ベンガル虎」が現れる。誰かが〔戦闘〕で難易度11の判定に成功すると、血戦を回避できる。",
  645. "「ここかなぁ~」治療の結果、変なツボをつかれたらしく、このセッションの間、〔破壊力〕が9に、〔反応力〕が1になる。",
  646. "「芸術的な内臓をしている」希望すれば、あなたの腎臓を《トランク》1つで買ってくれる。",
  647. "急患が大量に運ばれてくる。これ以降、このセッション終了時まで、乃木クリニックの治療の価格が、すべて1上昇する。",
  648. "乃木センセイの本気が炸裂! 美形タイプの男性キャラクターが1人いるたびに、治療の成功度が自動的に+2される。",
  649. "「だって、字ぃ読めないしぃ」リョータが点滴を間違える。サイコロを1個振り、下記のドラッグを摂取してしまう。1:《トルエン》 2:《ヘロイン》 3:《ハルシオン》 4《エクスタシー》 5:《コカイン》 6:《シャブ》",
  650. "「ウッソ、マッジ!?」待合室で読みたかった雑誌のバックナンバーを発見。〔精神点〕が全快し、トラウマを受けていればそれも1点回復する。",
  651. "医療ミス! サイコロを1個振り、1~4ならメスが、5~6ならランダムに趣味おたから1個が手術のミスで身体の中に残ってしまう。メスが身体に残っているキャラクターは、ファンブルを起こすたびに1ダメージを受けてしまう。重症の治療の判定に成功すると、中のアイテムを取り出すことができる。",
  652. "治療のついでに身体の異常が発見される。男性なら性病で鼻がもげ〔恋愛〕が1点減少、女性なら子供ができていることがわかる。",
  653. "奇跡的な治療のワザ! 治療判定の結果に関わらず〔肉体点〕が全快する。"
  654. ]
  655. ),
  656. "CollegeIT" => DiceTable::Table.new(
  657. "大学イベント表",
  658. "2D6",
  659. [
  660. "運動家に勧誘される。〔精神点〕を2点減少する。",
  661. "痴情のもつれ! 自分のトリコの数を数える。1D6を振り、その数以下の目を出してしまった場合、刺されてしまう。〔肉体点〕に3ダメージ(セーブ不可)。",
  662. "バイトの張り紙が…… セッション中に、何でもいいのでおたからを手に入れていれば、セッション終了時にそれを《トランク》で買い取ってくれる。",
  663. "コンパに誘われる。次の日の夜にコンパに行くことができる。コンパに行ったキャラクターは〔恋愛〕で難易度9の判定に成功すると、「女子高生」と恋人になる。",
  664. "授業にもぐりこむ。すやすやと心地よい時間が過ぎ、〔精神点〕を6点回復する。",
  665. "サークルボックスでダベる。同じターンに、他の仲間がリンク判定を行っていれば、好きな情報イベント表を振ることができる。",
  666. "キャンパスでいちゃいちゃカップルに遭遇する。らぶらぶオーラにあてられる。",
  667. "代返を頼まれる。〔精神〕で難易度9の判定に成功しないと、次の日の朝は行動を行えない。その代わり、学食で一回おごってもらえる。",
  668. "教授の実験に付き合わされる。〔肉体〕で難易度9の判定に失敗すると、《LSD》を飲まされる。",
  669. "麻雀に誘われる。次の日の夜に麻雀に行くことができる。麻雀に行ったキャラクターは、〔犯罪〕で難易度9の判定を行い、その成功度分だけ〔サイフ〕を回復することができる。ただし、〔性業値〕の判定を行い「律」以外だと徹マンになり、その日は無理してしまう。",
  670. "恋愛フラグが起動。チームの異性のキャラクターをランダムに1人選び、その人のトリコになる。また、選ばれた異性のキャラクターもランダムに異性キャラクターを1人選び、その人のトリコになる。"
  671. ]
  672. ),
  673. "FatalVT" => DiceTable::Table.new(
  674. "乗物致命傷表",
  675. "2D6",
  676. [
  677. "乗物は破壊。乗物に乗車していたキャラクターは、性業値判定を行う。「激」か「迷」だった者は、大破に巻き込まれ、2D6点のダメージを受ける(セーブ不可)。",
  678. "「ひどい運転しやがって!」死んだかと思った乗物が幽霊自動車になって、襲いかかってくる。",
  679. "「今まで一緒に乗ってくれてありがとう」乗物が、最後にきみに語りかけてくる。炎上する乗物を眺めながら、思わず涙が流れる。乗物は破壊。乗物の持ち主は、〔精神点〕を2点回復。",
  680. "ハンドルがきかず、人をひいてしまう。乗物は破壊。〔犯罪〕で難易度9の判定に失敗すると「臭い飯表」を1回振ること。",
  681. "コロコロコロコロ……車輪が転がる。ダメだ。もう一歩も動かない。乗物が破壊される。",
  682. "壮絶なクラッシュ!! 乗物とその乗物に乗せていたアイテムがすべて破壊される。",
  683. "乗物に衝撃が走る! 〔精神〕で難易度9の判定を行う。失敗すると、その乗物に乗せていたアイテムがすべて破壊される。乗物は破壊される。",
  684. "バッテリーがあがってしまった。乗物が一時的に使用不能に。1ターン後、乗物の〔肉体点〕が1になる。",
  685. "「おい! 走ってくれ! 走ってくれよ!」乗物が一時的に使用不能に。1D6ラウンド後、〔肉体点〕が1になる。",
  686. "エンスト! 乗物が一時的に使用不能に。1D6ターン後、〔肉体点〕が1D6点回復する。",
  687. "「まだ走れるよ!」奇跡のような走り! さきほどのダメージを無効に。"
  688. ]
  689. ),
  690. "TimeUT" => DiceTable::Table.new(
  691. "時間切れ表",
  692. "2D6",
  693. [
  694. "は! 夢か。今までのことは夢だった。すべて世はこともなし。",
  695. "UFOが現れ、トラクタービームに牽引される。全員〔精神〕で難易度9の判定を行う。失敗したキャラクターは、1D6セッション別のキャラクターでセッションを行うまで、再利用できなくなる。",
  696. "まわりでバタバタと人が倒れ始める。新型インフルエンザウイルスが、知性を持ち始め、突如人類に反旗を翻す。全員、〔肉体〕で難易度9の判定を行う。失敗したキャラクターは、〔肉体〕が1点減少する。",
  697. "急に、家のガスコンロを消したかどうか気になり始める。全員、〔生活〕で難易度9の判定を行う。失敗したキャラクターは、本当に火を消し忘れていた。家が火事になり、〔アジト装備〕がすべて破壊される。",
  698. "突如、みんなが歌い踊り出す。全員、〔教養〕で難易度9の判定を行う。失敗したキャラクターは、リズムを外して、トラウマを1点受ける。",
  699. "内戦勃発! 派手な市街戦が開始される。全員、〔戦闘〕で難易度9の判定を行う。失敗したキャラクターは、2D6点のダメージを受ける。内戦は3日後に終結する。",
  700. "いやーん、まいっちんぐ。200人の裸の美女が目の前を走りさっていく。一体何が起きたんだろう? 全員、〔恋愛〕で難易度9の判定を行う。失敗したキャラクターは、いつの間にか、その集団に呑み込まれ……トラウマを1点受ける。",
  701. "ビルの上から、大量のお札が降ってくる。皆、我を忘れて、それに群がり始める。全員、〔犯罪〕で難易度9の判定を行う。失敗したキャラクターは、〔通常装備〕欄からランダムにアイテム1つを失う。",
  702. "聖者が街にやってくる。「悔い改めよ!」全員、〔精神〕で難易度9の判定を行う。失敗したキャラクターは、好きなカルマ1種類の異能と代償が1つずつ未修得の状態になる。",
  703. "地獄の釜が開く。街に死者たちがあふれ出す。全員〔肉体〕で難易度9の判定を行う。失敗したキャラクターは、屍人になる。",
  704. "たらら、たらら、たらららら、たらららら♪ 大阪湾に怪獣王が現れる。大阪市は大混乱に! 全員、爆発4の効果を適用される。"
  705. ]
  706. ),
  707. }.transform_keys(&:upcase).freeze
  708. 1 ALIASES = {
  709. "RFT" => "RomanceFumbleT",
  710. "GAT" => "GeneralAccidentT",
  711. "RomanceFT" => "RomanceFumbleT",
  712. "GeneralAT" => "GeneralAccidentT",
  713. "RFumbleT" => "RomanceFumbleT",
  714. "GAccidentT" => "GeneralAccidentT",
  715. }.transform_keys(&:upcase).transform_values(&:upcase).freeze
  716. end
  717. end
  718. end

lib/bcdice/game_system/sword_world/rating_lexer.rb

94.44% lines covered

75.0% branches covered

18 relevant lines. 17 lines covered and 1 lines missed.
8 total branches, 6 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "strscan"
  3. 1 module BCDice
  4. 1 module GameSystem
  5. 1 class SwordWorld < Base
  6. 1 class RatingLexer
  7. 1 SYMBOLS = {
  8. "+" => :PLUS,
  9. "-" => :MINUS,
  10. "*" => :ASTERISK,
  11. "/" => :SLASH,
  12. "(" => :PARENL,
  13. ")" => :PARENR,
  14. "[" => :BRACKETL,
  15. "]" => :BRACKETR,
  16. "@" => :AT,
  17. "#" => :SHARP,
  18. "$" => :DOLLAR,
  19. "~" => :TILDE,
  20. }.freeze
  21. 1 def initialize(source)
  22. # sourceが空文字だとString#splitが空になる
  23. 624 then: 624 else: 0 then: 624 else: 0 source = source&.split(" ", 2)&.first || ""
  24. 624 @scanner = StringScanner.new(source)
  25. end
  26. 1 def next_token
  27. 4488 then: 613 else: 3875 return [false, "$"] if @scanner.eos?
  28. 3875 then: 1745 if (number = @scanner.scan(/\d+/))
  29. 1745 [:NUMBER, number.to_i]
  30. else: 2130 else
  31. 2130 char = @scanner.getch.upcase
  32. 2130 type = SYMBOLS[char] || char.to_sym
  33. 2130 [type, char]
  34. end
  35. end
  36. 1 def source
  37. @scanner.string
  38. end
  39. end
  40. end
  41. end
  42. end

lib/bcdice/game_system/sword_world/rating_options.rb

100.0% lines covered

100.0% branches covered

20 relevant lines. 20 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class SwordWorld < Base
  5. 1 class RatingOptions
  6. # @return [Integer, nil]
  7. 1 attr_accessor :critical
  8. # @return [Integer, nil]
  9. 1 attr_accessor :kept_modify
  10. # @return [Integer, nil]
  11. 1 attr_accessor :first_to
  12. # @return [Integer, nil]
  13. 1 attr_accessor :first_modify
  14. # @return [Integer, nil]
  15. 1 attr_accessor :first_modify_ssp
  16. # @return [Integer, nil]
  17. 1 attr_accessor :rateup
  18. # @return [Boolean, nil]
  19. 1 attr_accessor :greatest_fortune
  20. # @return [Integer, nil]
  21. 1 attr_accessor :semi_fixed_val
  22. # @return [Integer, nil]
  23. 1 attr_accessor :tmp_fixed_val
  24. # @return [Integer, nil]
  25. 1 attr_accessor :modifier
  26. # @return [Integer, nil]
  27. 1 attr_accessor :modifier_after_half
  28. # @return [Integer, nil]
  29. 1 attr_accessor :modifier_after_one_and_a_half
  30. 1 def settable_first_roll_adjust_option?
  31. 175 return first_modify.nil? && first_to.nil? && first_modify_ssp.nil?
  32. end
  33. 1 def settable_non_2d_roll_option?
  34. 82 return greatest_fortune.nil? && semi_fixed_val.nil? && tmp_fixed_val.nil?
  35. end
  36. end
  37. end
  38. end
  39. end

lib/bcdice/game_system/sword_world/rating_parsed.rb

100.0% lines covered

100.0% branches covered

55 relevant lines. 55 lines covered and 0 lines missed.
22 total branches, 22 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module GameSystem
  4. 1 class SwordWorld < Base
  5. 1 class RatingParsed
  6. # @return [Integer]
  7. 1 attr_accessor :rate
  8. # @return [Integer]
  9. 1 attr_accessor :critical
  10. # @return [Integer]
  11. 1 attr_accessor :kept_modify
  12. # @return [Integer]
  13. 1 attr_accessor :first_to
  14. # @return [Integer]
  15. 1 attr_accessor :first_modify
  16. # @return [Integer]
  17. 1 attr_accessor :first_modify_ssp
  18. # @return [Integer]
  19. 1 attr_accessor :rateup
  20. # @return [Boolean]
  21. 1 attr_accessor :greatest_fortune
  22. # @return [Integer]
  23. 1 attr_accessor :semi_fixed_val
  24. # @return [Integer]
  25. 1 attr_accessor :tmp_fixed_val
  26. # @return [Integer]
  27. 1 attr_accessor :modifier
  28. # @return [Integer, nil]
  29. 1 attr_accessor :modifier_after_half
  30. # @return [Integer, nil]
  31. 1 attr_accessor :modifier_after_one_and_a_half
  32. 1 def initialize(rate, modifier)
  33. 610 @rate = rate
  34. 610 @modifier = modifier
  35. 610 @critical = 13
  36. 610 @kept_modify = 0
  37. 610 @first_to = 0
  38. 610 @first_modify = 0
  39. 610 @first_modify_ssp = 0
  40. 610 @greatest_fortune = false
  41. 610 @rateup = 0
  42. 610 @semi_fixed_val = 0
  43. 610 @tmp_fixed_val = 0
  44. 610 @modifier_after_half = nil
  45. 610 @modifier_after_one_and_a_half = nil
  46. end
  47. # @return [Boolean]
  48. 1 def half
  49. 1375 return !@modifier_after_half.nil?
  50. end
  51. # @return [Boolean]
  52. 1 def one_and_a_half
  53. 1226 return !@modifier_after_one_and_a_half.nil?
  54. end
  55. # @return [Integer]
  56. 1 def min_critical
  57. 614 then: 584 if @semi_fixed_val <= 1
  58. 584 return 3
  59. else: 30 else
  60. 30 return (@semi_fixed_val + @kept_modify + 2).clamp(3, 13)
  61. end
  62. end
  63. # @return [Boolean]
  64. 1 def infinite_roll?
  65. 598 return critical < min_critical
  66. end
  67. # @return [String]
  68. 1 def to_s()
  69. 582 output = "KeyNo.#{@rate}"
  70. 582 then: 547 else: 35 output += "c[#{critical}]" if critical < 13
  71. 582 then: 44 else: 538 output += "m[#{Format.modifier(first_modify)}]" if first_modify != 0
  72. 582 then: 3 else: 579 output += "m[~#{Format.modifier(first_modify_ssp)}]" if first_modify_ssp != 0
  73. 582 then: 120 else: 462 output += "m[#{first_to}]" if first_to != 0
  74. 582 then: 34 else: 548 output += "r[#{rateup}]" if rateup != 0
  75. 582 then: 12 else: 570 output += "gf" if @greatest_fortune
  76. 582 then: 18 else: 564 output += "sf[#{semi_fixed_val}]" if semi_fixed_val != 0
  77. 582 then: 22 else: 560 output += "tf[#{tmp_fixed_val}]" if tmp_fixed_val != 0
  78. 582 then: 16 else: 566 output += "a[#{Format.modifier(kept_modify)}]" if kept_modify != 0
  79. 582 then: 364 else: 218 if @modifier != 0
  80. 364 output += Format.modifier(@modifier)
  81. end
  82. 582 return output
  83. end
  84. end
  85. end
  86. end
  87. end

lib/bcdice/game_system/sword_world/rating_parser.rb

94.42% lines covered

80.0% branches covered

215 relevant lines. 203 lines covered and 12 lines missed.
60 total branches, 48 branches covered and 12 branches missed.
    
  1. #
  2. # DO NOT MODIFY!!!!
  3. # This file is automatically generated by Racc 1.7.3
  4. # from Racc grammar file "rating_parser.y".
  5. #
  6. 1 require 'racc/parser.rb'
  7. 1 require "bcdice/arithmetic/node"
  8. 1 require "bcdice/enum"
  9. 1 require "bcdice/game_system/sword_world/rating_lexer"
  10. 1 require "bcdice/game_system/sword_world/rating_parsed"
  11. 1 require "bcdice/game_system/sword_world/rating_options"
  12. 1 module BCDice
  13. 1 module GameSystem
  14. 1 class SwordWorld < Base
  15. # SwordWorldの威力表コマンドをパースするクラス
  16. 1 class RatingParser < Racc::Parser
  17. # デフォルトの丸めを切り上げとしているが、SwordWorldには切り捨てもあるので決め切れない(四捨五入は現状ない)
  18. 1 def initialize(version: :v1_0, round_type: RoundType::CEIL)
  19. 624 super()
  20. 624 @version = version
  21. 624 @round_type = round_type
  22. end
  23. 1 def set_debug
  24. 24 @yydebug = true
  25. 24 return self
  26. end
  27. # @param source [String]
  28. # @return [BCDice::GameSystem::SwordWorld::RatingParsed, nil]
  29. 1 def parse(source)
  30. 624 @lexer = RatingLexer.new(source)
  31. 624 do_parse()
  32. rescue ParseError, ZeroDivisionError
  33. 14 nil
  34. end
  35. 1 private
  36. 1 def parsed(rate, modifier, option)
  37. 610 RatingParsed.new(rate, modifier).tap do |p|
  38. 610 then: 25 else: 585 p.kept_modify = option.kept_modify&.eval(@round_type) || 0
  39. 610 p.first_to = option.first_to || 0
  40. 610 p.first_modify = option.first_modify || 0
  41. 610 p.first_modify_ssp = option.first_modify_ssp || 0
  42. 610 then: 40 else: 570 p.rateup = option.rateup&.eval(@round_type) || 0
  43. 610 then: 14 else: 596 p.greatest_fortune = option.greatest_fortune if !option.greatest_fortune.nil?
  44. 610 then: 32 else: 578 p.semi_fixed_val = option.semi_fixed_val&.clamp(1, 6) || 0
  45. 610 then: 24 else: 586 p.tmp_fixed_val = option.tmp_fixed_val&.clamp(1, 6) || 0
  46. 610 then: 63 else: 547 p.modifier_after_half = option.modifier_after_half&.eval(@round_type)
  47. 610 then: 9 else: 601 p.modifier_after_one_and_a_half = option.modifier_after_one_and_a_half&.eval(@round_type)
  48. 610 then: 359 else: 251 then: 359 else: 251 then: 34 else: 217 p.critical = option.critical&.eval(@round_type)&.clamp(0, 13) || (p.half || p.one_and_a_half ? 13 : 10)
  49. end
  50. end
  51. 1 def next_token
  52. 4488 @lexer.next_token
  53. end
  54. ##### State transition tables begin ###
  55. 1 racc_action_table = [
  56. 36, 66, 67, 27, 28, 5, 68, 3, 4, 37,
  57. 38, 18, 16, 17, 19, 6, 20, 21, 23, 24,
  58. 39, 64, 65, 5, 13, 9, 14, 22, 15, 18,
  59. 16, 17, 19, 10, 20, 21, 23, 24, 64, 65,
  60. 64, 65, 13, 11, 14, 22, 15, 18, 16, 17,
  61. 19, 5, 20, 21, 23, 24, 34, 41, 34, 43,
  62. 13, 44, 14, 22, 15, 30, 31, 30, 31, 33,
  63. 34, 33, 34, 64, 65, 64, 65, 34, 45, 30,
  64. 31, 30, 31, 33, 34, 33, 30, 31, 53, 34,
  65. 33, 34, 58, 30, 31, 59, 34, 33, 30, 31,
  66. 30, 31, 33, 34, 33, 30, 31, 60, 34, 33,
  67. 34, 62, 30, 31, 63, 34, 33, 30, 31, 30,
  68. 31, 33, 34, 33, 30, 31, 69, 34, 33, 34,
  69. nil, 30, 31, nil, 34, 33, 30, 31, 30, 31,
  70. 33, nil, 33, 30, 31, 64, 65, 33, 64, 65 ]
  71. 1 racc_action_check = [
  72. 15, 56, 56, 12, 12, 0, 56, 0, 0, 15,
  73. 15, 7, 7, 7, 7, 1, 7, 7, 7, 7,
  74. 15, 47, 47, 3, 7, 4, 7, 7, 7, 25,
  75. 25, 25, 25, 5, 25, 25, 25, 25, 49, 49,
  76. 51, 51, 25, 6, 25, 25, 25, 50, 50, 50,
  77. 50, 9, 50, 50, 50, 50, 13, 17, 14, 19,
  78. 50, 20, 50, 50, 50, 13, 13, 14, 14, 13,
  79. 16, 14, 18, 52, 52, 57, 57, 22, 21, 16,
  80. 16, 18, 18, 16, 23, 18, 22, 22, 29, 24,
  81. 22, 27, 37, 23, 23, 38, 28, 23, 24, 24,
  82. 27, 27, 24, 30, 27, 28, 28, 39, 31, 28,
  83. 33, 44, 30, 30, 45, 41, 30, 31, 31, 33,
  84. 33, 31, 64, 33, 41, 41, 60, 65, 41, 66,
  85. nil, 64, 64, nil, 67, 64, 65, 65, 66, 66,
  86. 65, nil, 66, 67, 67, 72, 72, 67, 73, 73 ]
  87. 1 racc_action_pointer = [
  88. 2, 15, nil, 20, 20, 31, 43, 7, nil, 48,
  89. nil, nil, -8, 54, 56, -2, 68, 52, 70, 51,
  90. 53, 70, 75, 82, 87, 25, nil, 89, 94, 70,
  91. 101, 106, nil, 108, nil, nil, nil, 90, 93, 96,
  92. nil, 113, nil, nil, 109, 112, nil, 8, nil, 25,
  93. 43, 27, 60, nil, nil, nil, -10, 62, nil, nil,
  94. 124, nil, nil, nil, 120, 125, 127, 132, nil, nil,
  95. nil, nil, 132, 135 ]
  96. 1 racc_action_default = [
  97. -37, -37, -5, -37, -37, -37, -37, -1, -5, -37,
  98. -4, 74, -6, -37, -37, -37, -13, -37, -37, -37,
  99. -37, -37, -37, -37, -37, -2, -5, -37, -37, -37,
  100. -37, -37, -34, -37, -36, -8, -9, -37, -37, -37,
  101. -14, -15, -17, -18, -37, -37, -21, -22, -31, -23,
  102. -3, -24, -25, -7, -32, -33, -37, -28, -10, -11,
  103. -37, -16, -19, -20, -37, -37, -37, -37, -35, -12,
  104. -29, -30, -26, -27 ]
  105. 1 racc_goto_table = [
  106. 29, 35, 7, 40, 1, 42, 47, 49, 25, 46,
  107. 51, 52, 2, 56, nil, 8, 57, 54, 55, nil,
  108. nil, 26, nil, nil, nil, nil, 50, nil, 61, nil,
  109. nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  110. nil, nil, nil, nil, nil, nil, nil, nil, nil, 72,
  111. 73, 70, 71 ]
  112. 1 racc_goto_check = [
  113. 5, 5, 3, 5, 1, 5, 6, 6, 3, 5,
  114. 6, 6, 2, 7, nil, 2, 6, 5, 5, nil,
  115. nil, 2, nil, nil, nil, nil, 3, nil, 5, nil,
  116. nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  117. nil, nil, nil, nil, nil, nil, nil, nil, nil, 6,
  118. 6, 5, 5 ]
  119. 1 racc_goto_pointer = [
  120. nil, 4, 12, 0, nil, -13, -17, -20, nil ]
  121. 1 racc_goto_default = [
  122. nil, nil, nil, nil, 12, 48, nil, nil, 32 ]
  123. 1 racc_reduce_table = [
  124. 0, 0, :racc_error,
  125. 2, 24, :_reduce_1,
  126. 3, 24, :_reduce_2,
  127. 4, 24, :_reduce_3,
  128. 2, 25, :_reduce_4,
  129. 0, 26, :_reduce_5,
  130. 2, 26, :_reduce_6,
  131. 4, 26, :_reduce_7,
  132. 3, 26, :_reduce_8,
  133. 3, 26, :_reduce_9,
  134. 4, 26, :_reduce_10,
  135. 4, 26, :_reduce_11,
  136. 5, 26, :_reduce_12,
  137. 2, 26, :_reduce_13,
  138. 3, 26, :_reduce_14,
  139. 3, 26, :_reduce_15,
  140. 4, 26, :_reduce_16,
  141. 3, 26, :_reduce_17,
  142. 3, 26, :_reduce_18,
  143. 4, 26, :_reduce_19,
  144. 4, 26, :_reduce_20,
  145. 3, 26, :_reduce_21,
  146. 2, 27, :_reduce_22,
  147. 2, 27, :_reduce_23,
  148. 3, 27, :_reduce_24,
  149. 3, 27, :_reduce_25,
  150. 3, 30, :_reduce_26,
  151. 3, 30, :_reduce_27,
  152. 1, 30, :_reduce_none,
  153. 3, 29, :_reduce_29,
  154. 3, 29, :_reduce_30,
  155. 1, 29, :_reduce_none,
  156. 2, 28, :_reduce_32,
  157. 2, 28, :_reduce_33,
  158. 1, 28, :_reduce_none,
  159. 3, 31, :_reduce_35,
  160. 1, 31, :_reduce_36 ]
  161. 1 racc_reduce_n = 37
  162. 1 racc_shift_n = 74
  163. 1 racc_token_table = {
  164. false => 0,
  165. :error => 1,
  166. :NUMBER => 2,
  167. :K => 3,
  168. :R => 4,
  169. :H => 5,
  170. :O => 6,
  171. :G => 7,
  172. :F => 8,
  173. :S => 9,
  174. :T => 10,
  175. :PLUS => 11,
  176. :MINUS => 12,
  177. :ASTERISK => 13,
  178. :SLASH => 14,
  179. :PARENL => 15,
  180. :PARENR => 16,
  181. :BRACKETL => 17,
  182. :BRACKETR => 18,
  183. :AT => 19,
  184. :SHARP => 20,
  185. :DOLLAR => 21,
  186. :TILDE => 22 }
  187. 1 racc_nt_base = 23
  188. 1 racc_use_result_var = true
  189. Racc_arg = [
  190. 1 racc_action_table,
  191. racc_action_check,
  192. racc_action_default,
  193. racc_action_pointer,
  194. racc_goto_table,
  195. racc_goto_check,
  196. racc_goto_default,
  197. racc_goto_pointer,
  198. racc_nt_base,
  199. racc_reduce_table,
  200. racc_token_table,
  201. racc_shift_n,
  202. racc_reduce_n,
  203. racc_use_result_var ]
  204. 1 then: 1 else: 0 Ractor.make_shareable(Racc_arg) if defined?(Ractor)
  205. 1 Racc_token_to_s_table = [
  206. "$end",
  207. "error",
  208. "NUMBER",
  209. "K",
  210. "R",
  211. "H",
  212. "O",
  213. "G",
  214. "F",
  215. "S",
  216. "T",
  217. "PLUS",
  218. "MINUS",
  219. "ASTERISK",
  220. "SLASH",
  221. "PARENL",
  222. "PARENR",
  223. "BRACKETL",
  224. "BRACKETR",
  225. "AT",
  226. "SHARP",
  227. "DOLLAR",
  228. "TILDE",
  229. "$start",
  230. "expr",
  231. "rate",
  232. "option",
  233. "modifier",
  234. "unary",
  235. "mul",
  236. "add",
  237. "term" ]
  238. 1 then: 1 else: 0 Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
  239. 1 Racc_debug_parser = false
  240. ##### State transition tables end #####
  241. # reduce 0 omitted
  242. 1 def _reduce_1(val, _values, result)
  243. 574 rate, option = val
  244. 574 modifier = option.modifier || Arithmetic::Node::Number.new(0)
  245. 574 result = parsed(rate, modifier.eval(@round_type), option)
  246. 574 result
  247. end
  248. 1 def _reduce_2(val, _values, result)
  249. 32 _, rate, option = val
  250. 32 then: 1 else: 31 raise ParseError if option.modifier_after_one_and_a_half
  251. 31 option.modifier_after_half ||= Arithmetic::Node::Number.new(0)
  252. 31 modifier = option.modifier || Arithmetic::Node::Number.new(0)
  253. 31 result = parsed(rate, modifier.eval(@round_type), option)
  254. 31 result
  255. end
  256. 1 def _reduce_3(val, _values, result)
  257. 6 _, _, rate, option = val
  258. 6 then: 1 else: 5 raise ParseError if option.modifier_after_half
  259. 5 option.modifier_after_one_and_a_half ||= Arithmetic::Node::Number.new(0)
  260. 5 modifier = option.modifier || Arithmetic::Node::Number.new(0)
  261. 5 result = parsed(rate, modifier.eval(@round_type), option)
  262. 5 result
  263. end
  264. 1 def _reduce_4(val, _values, result)
  265. 624 result = val[1].to_i
  266. 624 result
  267. end
  268. 1 def _reduce_5(val, _values, result)
  269. 624 result = RatingOptions.new
  270. 624 result
  271. end
  272. 1 def _reduce_6(val, _values, result)
  273. 388 option, term = val
  274. 388 else: 387 then: 1 raise ParseError unless option.modifier.nil?
  275. 387 option.modifier = term
  276. 387 result = option
  277. 387 result
  278. end
  279. 1 def _reduce_7(val, _values, result)
  280. 120 option, _, term, _ = val
  281. 120 else: 120 then: 0 raise ParseError unless option.critical.nil?
  282. 120 option.critical = term
  283. 120 result = option
  284. 120 result
  285. end
  286. 1 def _reduce_8(val, _values, result)
  287. 244 option, _, term = val
  288. 244 else: 243 then: 1 raise ParseError unless option.critical.nil?
  289. 243 option.critical = term
  290. 243 result = option
  291. 243 result
  292. end
  293. 1 def _reduce_9(val, _values, result)
  294. 121 option, _, term = val
  295. 121 else: 121 then: 0 raise ParseError unless option.settable_first_roll_adjust_option?
  296. 121 option.first_to = term.to_i
  297. 121 result = option
  298. 121 result
  299. end
  300. 1 def _reduce_10(val, _values, result)
  301. 51 option, _, _, term = val
  302. 51 else: 51 then: 0 raise ParseError unless option.settable_first_roll_adjust_option?
  303. 51 option.first_modify = term.to_i
  304. 51 result = option
  305. 51 result
  306. end
  307. 1 def _reduce_11(val, _values, result)
  308. option, _, _, term = val
  309. else: 0 then: 0 raise ParseError unless option.settable_first_roll_adjust_option?
  310. option.first_modify = -(term.to_i)
  311. result = option
  312. result
  313. end
  314. 1 def _reduce_12(val, _values, result)
  315. 3 option, _, _, _, term = val
  316. 3 else: 3 then: 0 raise ParseError unless @version == :v2_5 && option.settable_first_roll_adjust_option?
  317. 3 option.first_modify_ssp = term.to_i
  318. 3 result = option
  319. 3 result
  320. end
  321. 1 def _reduce_13(val, _values, result)
  322. 25 option, _ = val
  323. 25 else: 25 then: 0 raise ParseError unless option.modifier_after_half.nil?
  324. 25 option.modifier_after_half = Arithmetic::Node::Number.new(0)
  325. 25 result = option
  326. 25 result
  327. end
  328. 1 def _reduce_14(val, _values, result)
  329. 15 option, _, term = val
  330. 15 else: 15 then: 0 raise ParseError unless option.modifier_after_half.nil?
  331. 15 option.modifier_after_half = term
  332. 15 result = option
  333. 15 result
  334. end
  335. 1 def _reduce_15(val, _values, result)
  336. 4 option, _, _ = val
  337. 4 then: 0 else: 4 raise ParseError if option.modifier_after_one_and_a_half
  338. 4 option.modifier_after_one_and_a_half = Arithmetic::Node::Number.new(0)
  339. 4 result = option
  340. 4 result
  341. end
  342. 1 def _reduce_16(val, _values, result)
  343. 2 option, _, _, term = val
  344. 2 then: 0 else: 2 raise ParseError if option.modifier_after_one_and_a_half
  345. 2 option.modifier_after_one_and_a_half = term
  346. 2 result = option
  347. 2 result
  348. end
  349. 1 def _reduce_17(val, _values, result)
  350. 41 option, _, term = val
  351. 41 else: 40 then: 1 raise ParseError unless [:v2_5, :v2_0].include?(@version) && option.rateup.nil?
  352. 40 option.rateup = term
  353. 40 result = option
  354. 40 result
  355. end
  356. 1 def _reduce_18(val, _values, result)
  357. 19 option, _, _ = val
  358. 19 else: 18 then: 1 raise ParseError unless [:v2_5, :v2_0].include?(@version) && option.settable_non_2d_roll_option?
  359. 18 option.greatest_fortune = true
  360. 18 result = option
  361. 18 result
  362. end
  363. 1 def _reduce_19(val, _values, result)
  364. 36 option, _, _, term = val
  365. 36 else: 34 then: 2 raise ParseError unless [:v2_5, :v2_0].include?(@version) && option.settable_non_2d_roll_option?
  366. 34 option.semi_fixed_val = term.to_i
  367. 34 result = option
  368. 34 result
  369. end
  370. 1 def _reduce_20(val, _values, result)
  371. 28 option, _, _, term = val
  372. 28 else: 24 then: 4 raise ParseError unless [:v2_5, :v2_0].include?(@version) && option.settable_non_2d_roll_option?
  373. 24 option.tmp_fixed_val = term.to_i
  374. 24 result = option
  375. 24 result
  376. end
  377. 1 def _reduce_21(val, _values, result)
  378. 27 option, _, term = val
  379. 27 else: 25 then: 2 raise ParseError unless @version == :v2_5 && option.kept_modify.nil?
  380. 25 option.kept_modify = term
  381. 25 result = option
  382. 25 result
  383. end
  384. 1 def _reduce_22(val, _values, result)
  385. 306 result = val[1]
  386. 306 result
  387. end
  388. 1 def _reduce_23(val, _values, result)
  389. 82 result = Arithmetic::Node::Negative.new(val[1])
  390. 82 result
  391. end
  392. 1 def _reduce_24(val, _values, result)
  393. 42 result = Arithmetic::Node::BinaryOp.new(val[0], :+, val[2])
  394. 42 result
  395. end
  396. 1 def _reduce_25(val, _values, result)
  397. 1 result = Arithmetic::Node::BinaryOp.new(val[0], :-, val[2])
  398. 1 result
  399. end
  400. 1 def _reduce_26(val, _values, result)
  401. result = Arithmetic::Node::BinaryOp.new(val[0], :+, val[2])
  402. result
  403. end
  404. 1 def _reduce_27(val, _values, result)
  405. result = Arithmetic::Node::BinaryOp.new(val[0], :-, val[2])
  406. result
  407. end
  408. # reduce 28 omitted
  409. 1 def _reduce_29(val, _values, result)
  410. 1 result = Arithmetic::Node::BinaryOp.new(val[0], :*, val[2])
  411. 1 result
  412. end
  413. 1 def _reduce_30(val, _values, result)
  414. 1 result = Arithmetic::Node::DivideWithGameSystemDefault.new(val[0], val[2])
  415. 1 result
  416. end
  417. # reduce 31 omitted
  418. 1 def _reduce_32(val, _values, result)
  419. 23 result = val[1]
  420. 23 result
  421. end
  422. 1 def _reduce_33(val, _values, result)
  423. 4 result = Arithmetic::Node::Negative.new(val[1])
  424. 4 result
  425. end
  426. # reduce 34 omitted
  427. 1 def _reduce_35(val, _values, result)
  428. result = val[1]
  429. result
  430. end
  431. 1 def _reduce_36(val, _values, result)
  432. 882 result = Arithmetic::Node::Number.new(val[0])
  433. 882 result
  434. end
  435. 1 def _reduce_none(val, _values, result)
  436. val[0]
  437. end
  438. end # class RatingParser
  439. end
  440. end
  441. end

lib/bcdice/game_system/sword_world/transcendent_test.rb

100.0% lines covered

100.0% branches covered

53 relevant lines. 53 lines covered and 0 lines missed.
17 total branches, 17 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "bcdice/result"
  3. 1 require "bcdice/translate"
  4. 1 module BCDice
  5. 1 module GameSystem
  6. 1 class SwordWorld2_0 < SwordWorld
  7. # 超越判定のノード
  8. 1 class TranscendentTest
  9. 1 include Translate
  10. # @param [Integer] critical_value クリティカル値
  11. # @param [Integer] modifier 修正値
  12. # @param [String, nil] cmp_op 比較演算子(> または >=)
  13. # @param [Integer, nil] target 目標値
  14. 1 def initialize(critical_value, modifier, cmp_op, target, locale)
  15. 84 @critical_value = critical_value
  16. 84 @modifier = modifier
  17. 84 @cmp_op = cmp_op
  18. 84 @target = target
  19. 84 @locale = locale
  20. 84 @modifier_str = Format.modifier(@modifier)
  21. 84 @expression = node_expression()
  22. end
  23. # 超越判定を行う
  24. # @param randomizer [Randomizer]
  25. # @return [String]
  26. 1 def execute(randomizer)
  27. 84 then: 4 else: 80 if @critical_value < 3
  28. 4 return translate("SwordWorld2_0.transcendent_critical_too_small", expression: @expression)
  29. end
  30. 80 first_value_group = randomizer.roll_barabara(2, 6)
  31. 80 value_groups = [first_value_group]
  32. 80 fumble = first_value_group == [1, 1]
  33. 80 critical = first_value_group == [6, 6]
  34. 80 else: 8 then: 72 unless fumble
  35. 72 body: 112 while sum_of_dice(value_groups.last) >= @critical_value
  36. 112 value_groups.push(randomizer.roll_barabara(2, 6))
  37. end
  38. end
  39. 80 sum = sum_of_dice(value_groups)
  40. 80 total_sum = sum + @modifier
  41. 80 result = result_status(total_sum, value_groups.length, fumble, critical)
  42. result_str = {
  43. 80 success: translate("success"),
  44. failure: translate("failure"),
  45. super_success: translate("SwordWorld2_0.super_success"),
  46. critical: translate("SwordWorld.critical"),
  47. fumble: translate("SwordWorld.fumble"),
  48. }.freeze[result]
  49. parts = [
  50. 80 "(#{@expression})",
  51. "#{dice_str(value_groups, sum)}#{@modifier_str}",
  52. total_sum,
  53. result_str,
  54. ].compact
  55. 80 return Result.new.tap do |r|
  56. 80 r.text = parts.join(" > ")
  57. 80 r.fumble = result == :fumble
  58. 80 r.critical = result == :critical
  59. 80 r.success = [:success, :super_success, :critical].include?(result)
  60. 80 r.failure = [:failure, :fumble].include?(result)
  61. end
  62. end
  63. 1 private
  64. # 数式表記を返す
  65. # @return [String]
  66. 1 def node_expression
  67. 84 lhs = "2D6@#{@critical_value}#{@modifier_str}"
  68. 84 then: 72 else: 12 return @target ? "#{lhs}#{@cmp_op}#{@target}" : lhs
  69. end
  70. # 出目の合計を返す
  71. # @param [(Integer, Integer), Array<(Integer, Integer)>] value_groups
  72. # 出目のグループまたはその配列
  73. # @return [Integer]
  74. 1 def sum_of_dice(value_groups)
  75. 264 value_groups.flatten.sum
  76. end
  77. # ダイス部分の文字列を返す
  78. # @param [Array<(Integer, Integer)>] value_groups 出目のグループの配列
  79. # @param [Integer] sum 出目の合計
  80. # @return [String]
  81. 1 def dice_str(value_groups, sum)
  82. value_groups_str =
  83. 80 value_groups
  84. 192 .map { |values| "[#{values.join(',')}]" }
  85. .join
  86. 80 return "#{sum}#{value_groups_str}"
  87. end
  88. # 判定結果の文字列を返す
  89. # @param [Integer] total_sum 合計値
  90. # @param [Integer] n_value_groups 出目のグループの数
  91. # @param [Boolean] fumble ファンブルかどうか
  92. # @param [Boolean] critical クリティカルかどうか
  93. # @return [Symbol]
  94. 1 def result_status(total_sum, n_value_groups, fumble, critical)
  95. 80 else: 72 then: 8 return :no_target unless @target
  96. 72 then: 8 else: 64 return :fumble if fumble
  97. 64 then: 8 else: 56 return :critical if critical
  98. 56 if total_sum.send(@cmp_op, @target)
  99. then: 50 # 振り足しが行われ、合計値が41以上ならば「超成功」
  100. 50 then: 26 else: 24 n_value_groups >= 2 && total_sum >= 41 ? :super_success : :success
  101. else: 6 else
  102. 6 :failure
  103. end
  104. end
  105. end
  106. end
  107. end
  108. end

lib/bcdice/loader.rb

85.71% lines covered

50.0% branches covered

14 relevant lines. 12 lines covered and 2 lines missed.
2 total branches, 1 branches covered and 1 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 class << self
  4. # IDを指定してゲームシステムのクラスを取得する
  5. # ゲームシステム一覧がロードされていなければロードする
  6. #
  7. # @param id [String] ID
  8. # @return [Class, nil]
  9. 1 def game_system_class(id)
  10. 2575161 all_game_systems.find { |game_system| id == game_system::ID }
  11. end
  12. # ゲームシステムのクラス一覧を返す
  13. # ゲームシステム一覧がロードされていなければロードする
  14. #
  15. # @return [Array<Class>]
  16. 1 def all_game_systems()
  17. 17704 require "bcdice/game_system"
  18. 5151864 BCDice::GameSystem.constants.map { |class_name| BCDice::GameSystem.const_get(class_name) }
  19. end
  20. # IDを指定して対象のソースコードを動的にロードし、そのクラスを取得する
  21. #
  22. # @param id [String] ID
  23. # @return [Class, nil]
  24. 1 def dynamic_load(id)
  25. 1 class_name = id.tr(":.", "_")
  26. # 対象ディレクトリの外にあるファイルをロードされないように制約を設ける
  27. 1 else: 1 then: 0 unless /\A[A-Z]\w*\z/.match?(class_name)
  28. return nil
  29. end
  30. 1 require "bcdice/game_system/#{class_name}"
  31. 1 return BCDice::GameSystem.const_get(class_name)
  32. rescue LoadError, NameError
  33. return nil
  34. end
  35. end
  36. end

lib/bcdice/normalize.rb

80.0% lines covered

77.78% branches covered

15 relevant lines. 12 lines covered and 3 lines missed.
9 total branches, 7 branches covered and 2 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. 1 module Normalize
  4. 1 module_function
  5. # 比較演算子をシンボルに正規化する
  6. #
  7. # @param op [String]
  8. # @return [Symbol, nil]
  9. 1 def comparison_operator(op)
  10. 2184 else: 160 case op
  11. when: 494 when /<=|=</
  12. 494 :<=
  13. when: 1391 when />=|=>/
  14. 1391 :>=
  15. when: 22 when /<>|!=|=!/
  16. 22 :'!='
  17. when: 30 when /</
  18. 30 :<
  19. when: 73 when />/
  20. 73 :>
  21. when: 14 when /=/
  22. 14 :==
  23. end
  24. end
  25. # 目標値を正規化する
  26. #
  27. # @param val [String]
  28. # @return [Integer, String] 整数か'?'
  29. 1 def target_number(val)
  30. then: 0 if val == "?"
  31. val
  32. else: 0 else
  33. val.to_i
  34. end
  35. end
  36. end
  37. end

lib/bcdice/preprocessor.rb

100.0% lines covered

100.0% branches covered

28 relevant lines. 28 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. # 入力文字列に対して前処理を行う
  4. #
  5. # @example
  6. # Preprocessor.process(
  7. # "1d6+4D+(3*4) 切り取られる部分",
  8. # game_system
  9. # ) #=> "1d6+4D6+7"
  10. 1 class Preprocessor
  11. # @param (see #initialize)
  12. # @return [String]
  13. 1 def self.process(text, game_system)
  14. 17969 Preprocessor.new(text, game_system).process()
  15. end
  16. # @param text [String]
  17. # @param game_system [Base]
  18. 1 def initialize(text, game_system)
  19. 17969 @text = text
  20. 17969 @game_system = game_system
  21. end
  22. # @return [String]
  23. 1 def process
  24. 17969 trim_after_whitespace()
  25. 17969 replace_parentheses()
  26. 17969 @text = @game_system.change_text(@text)
  27. 17969 replace_implicit_d()
  28. 17969 return @text
  29. end
  30. 1 private
  31. # 空白より前だけを取る
  32. 1 def trim_after_whitespace()
  33. 17969 @text = @text.strip.split(/\s/, 2).first
  34. end
  35. # カッコ書きの数式を事前計算する
  36. 1 def replace_parentheses
  37. 17969 loop do
  38. 18507 prev = @text
  39. 18507 @text = @text.gsub(%r{\([\d/+*\-CURF]+\)}) do |expr|
  40. 566 Arithmetic.eval(expr, @game_system.round_type) || expr
  41. end
  42. 18507 then: 17969 else: 538 break if prev == @text
  43. end
  44. end
  45. # nDをゲームシステムに応じて置き換える
  46. 1 def replace_implicit_d
  47. 17969 @text = @text.gsub(/(\d+)D([^\w]|$)/i) do
  48. 64 times = Regexp.last_match(1)
  49. 64 sides = @game_system.sides_implicit_d
  50. 64 trailer = Regexp.last_match(2)
  51. 64 "#{times}D#{sides}#{trailer}"
  52. end
  53. end
  54. end
  55. end

lib/bcdice/randomizer.rb

100.0% lines covered

100.0% branches covered

57 relevant lines. 57 lines covered and 0 lines missed.
13 total branches, 13 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. # 乱数生成器
  4. 1 class Randomizer
  5. 1 UPPER_LIMIT_DICE_TIMES = 200
  6. 1 UPPER_LIMIT_DICE_SIDES = 10000
  7. 1 UPPER_LIMIT_RANDS = 10000
  8. 1 def initialize
  9. 35744 @rand_results = []
  10. 35744 @detailed_rand_results = []
  11. end
  12. # @return [Array<Array<(Integer, Integer)>>] ダイスの出目一覧
  13. 1 attr_reader :rand_results
  14. # @return [Array<DetailedRandResult>]
  15. 1 attr_reader :detailed_rand_results
  16. # 実行したダイスロールの詳細
  17. # @!attribute [rw] kind
  18. # @return [Symbol]
  19. # @!attribute [rw] sides
  20. # @return [Integer] ダイスロールしたダイスの面数
  21. # @!attribute [rw] value
  22. # @return [Integer] 値
  23. 1 DetailedRandResult = Struct.new(:kind, :sides, :value)
  24. # 複数個のダイスを振る
  25. #
  26. # @param times [Integer] 振るダイスの個数
  27. # @param sides [Integer] ダイスの面数
  28. # @return [Array<Integer>] ダイスの出目一覧
  29. 1 def roll_barabara(times, sides)
  30. 18441 then: 3 else: 18438 if @rand_results.size + times > UPPER_LIMIT_RANDS
  31. 3 raise TooManyRandsError
  32. end
  33. 18438 then: 149 else: 18289 if times <= 0 || times > UPPER_LIMIT_DICE_TIMES
  34. 149 return []
  35. end
  36. 70151 Array.new(times) { roll_once(sides) }
  37. end
  38. # 複数個のダイスを振って、その合計を求める
  39. #
  40. # @param times [Integer] 振るダイスの個数
  41. # @param sides [Integer] ダイスの面数
  42. # @return [Integer] 出目の合計
  43. 1 def roll_sum(times, sides)
  44. 4579 roll_barabara(times, sides).sum()
  45. end
  46. # 1回だけダイスロールを行う
  47. #
  48. # @param sides [Integer] ダイスの面数
  49. # @return [Integer] 1以上 *sides* 以下の値のいずれか
  50. 1 def roll_once(sides)
  51. 95305 then: 30 else: 95275 if sides <= 0 || sides > UPPER_LIMIT_DICE_SIDES
  52. 30 return 0
  53. end
  54. 95275 dice = rand_inner(sides)
  55. 95273 push_to_detail(:normal, sides, dice)
  56. 95273 return dice
  57. end
  58. # ダイス表などでindexを参照する用のダイスロール
  59. # @param sides [Integer]
  60. # @return [Integer] 0以上 *sides* 未満の整数
  61. 1 def roll_index(sides)
  62. 1008 roll_once(sides) - 1
  63. end
  64. # 十の位をd10を使って決定するためのダイスロール
  65. # @return [Integer] 0以上90以下で10の倍数となる整数
  66. 1 def roll_tens_d10()
  67. # rand_innerの戻り値を10倍すればすむ話なのだが、既存のテストとの互換性の為に処理をする
  68. 10815 dice = rand_inner(10)
  69. 10814 then: 1263 else: 9551 if dice == 10
  70. 1263 dice = 0
  71. end
  72. 10814 ret = dice * 10
  73. 10814 push_to_detail(:tens_d10, 10, ret)
  74. 10814 return ret
  75. end
  76. # d10を0~9として扱うダイスロール
  77. # @return [Integer] 0以上9以下の整数
  78. 1 def roll_d9()
  79. 10009 dice = rand_inner(10) - 1
  80. 10008 push_to_detail(:d9, 10, dice)
  81. 10008 return dice
  82. end
  83. # D66のダイスロールを行う
  84. # @param sort_type [Symbol] BCDice::D66SortType
  85. # @return [Integer]
  86. 1 def roll_d66(sort_type)
  87. 17831 dice_list = Array.new(2) { roll_once(6) }
  88. 5943 else: 70 case sort_type
  89. when: 5871 when D66SortType::ASC
  90. 5871 dice_list.sort!
  91. when: 2 when D66SortType::DESC
  92. 2 dice_list.sort!.reverse!
  93. end
  94. 5943 return dice_list[0] * 10 + dice_list[1]
  95. end
  96. 1 private
  97. # @param sides [Integer]
  98. # @return [Integer] 1以上sides以下の整数
  99. 1 def rand_inner(sides)
  100. 116099 then: 4 else: 116095 if @rand_results.size >= UPPER_LIMIT_RANDS
  101. 4 raise TooManyRandsError
  102. end
  103. 116095 dice = random(sides)
  104. 116095 @rand_results << [dice, sides]
  105. 116095 return dice
  106. end
  107. # モックで上書きする用
  108. # @param sides [Integer]
  109. # @return [Integer] 1以上sides以下の整数
  110. 1 def random(sides)
  111. 60216 Kernel.rand(sides) + 1
  112. end
  113. # @param [Symbol] kind
  114. # @param [Integer] sides
  115. # @param [Integer] value
  116. 1 def push_to_detail(kind, sides, value)
  117. 116095 detail = DetailedRandResult.new(kind, sides, value)
  118. 116095 @detailed_rand_results.push(detail)
  119. end
  120. end
  121. 1 class TooManyRandsError < StandardError; end
  122. end

lib/bcdice/result.rb

100.0% lines covered

100.0% branches covered

47 relevant lines. 47 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. # ダイスロールの結果を表すクラス
  4. #
  5. # コマンドの結果の文字列や、成功/失敗/クリティカル/ファンブルの情報を保持する。
  6. # 成功/失敗は同時に発生しないこととする。
  7. # 成功/失敗のペアとクリティカル、ファンブルの三者は独立した要素とし、
  8. # 「クリティカルだが失敗」や「ファンブルだが成功でも失敗でもない」を許容する。
  9. 1 class Result
  10. 1 class << self
  11. # +success+ が設定された +Result+ を作成する
  12. #
  13. # @param text [String]
  14. # @return [Result]
  15. 1 def success(text)
  16. 1178 new.tap do |r|
  17. 1178 r.text = text
  18. 1178 r.success = true
  19. end
  20. end
  21. # +failure+ が設定された +Result+ を作成する
  22. #
  23. # @param text [String]
  24. # @return [Result]
  25. 1 def failure(text)
  26. 786 new.tap do |r|
  27. 786 r.text = text
  28. 786 r.failure = true
  29. end
  30. end
  31. # +success+ と +critical+ が設定された +Result+ を作成する
  32. #
  33. # @param text [String]
  34. # @return [Result]
  35. 1 def critical(text)
  36. 532 new.tap do |r|
  37. 532 r.text = text
  38. 532 r.critical = true
  39. 532 r.success = true
  40. end
  41. end
  42. # +failure+ と +fumble+ が設定された +Result+ を作成する
  43. #
  44. # @param text [String]
  45. # @return [Result]
  46. 1 def fumble(text)
  47. 444 new.tap do |r|
  48. 444 r.text = text
  49. 444 r.fumble = true
  50. 444 r.failure = true
  51. end
  52. end
  53. # その後の判定で何もすることがないことを示すために利用する
  54. #
  55. # @return [:nothing]
  56. 1 def nothing
  57. 1170 :nothing
  58. end
  59. end
  60. # @param text [String | nil]
  61. 1 def initialize(text = nil)
  62. 18135 @text = text
  63. 18135 @rands = nil
  64. 18135 @detailed_rands = nil
  65. 18135 @secret = false
  66. 18135 @success = false
  67. 18135 @failure = false
  68. 18135 @critical = false
  69. 18135 @fumble = false
  70. end
  71. 1 attr_accessor :text, :rands, :detailed_rands
  72. 1 attr_writer :secret, :success, :failure, :critical, :fumble
  73. # @return [Boolean]
  74. 1 def secret?
  75. 22493 @secret
  76. end
  77. # @return [Boolean]
  78. 1 def success?
  79. 17899 @success
  80. end
  81. # @return [Boolean]
  82. 1 def failure?
  83. 17617 @failure
  84. end
  85. # @return [Boolean]
  86. 1 def critical?
  87. 17764 @critical
  88. end
  89. # @return [Boolean]
  90. 1 def fumble?
  91. 18119 @fumble
  92. end
  93. # @param condition [Boolean]
  94. # @return [void]
  95. 1 def condition=(condition)
  96. 765 @success = condition
  97. 765 @failure = !condition
  98. end
  99. end
  100. end

lib/bcdice/translate.rb

100.0% lines covered

100.0% branches covered

4 relevant lines. 4 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. # i18n用のモジュール
  4. 1 module Translate
  5. # i18n用の翻訳メソッド
  6. # @param key [String]
  7. # @return [Object]
  8. 1 def translate(key, **options)
  9. 4964 I18n.translate(key, locale: @locale, raise: true, **options)
  10. end
  11. end
  12. end

lib/bcdice/user_defined_dice_table.rb

92.11% lines covered

77.78% branches covered

76 relevant lines. 70 lines covered and 6 lines missed.
27 total branches, 21 branches covered and 6 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module BCDice
  3. # テキストで定義したダイス表を実行するクラス
  4. #
  5. # @example
  6. # text = <<~TEXT
  7. # 飲み物表
  8. # 1D6
  9. # 1:水
  10. # 2:緑茶
  11. # 3:麦茶
  12. # 4:コーラ
  13. # 5:オレンジジュース
  14. # 6:選ばれし者の知的飲料
  15. # TEXT
  16. # table = BCDice::UserDefinedDiceTable.new(text)
  17. # table.valid?() #=> true
  18. # table.roll().text #=> "飲み物表(6) > 選ばれし者の知的飲料"
  19. # BCDice::UserDefinedDiceTable.eval(text) #=> #<BCDice::Result>
  20. #
  21. 1 class UserDefinedDiceTable
  22. 1 class << self
  23. # @param text [String]
  24. # @return [Result nil]
  25. 1 def roll(text)
  26. new(text).roll()
  27. end
  28. end
  29. # @param text [String] ダイス表のテキストデータ
  30. 1 def initialize(text)
  31. 21 @text = text
  32. 21 @rows = nil
  33. end
  34. # ダイス表をロールする
  35. # @param randomizer [Randomizer]
  36. # @return [Result, nil]
  37. 1 def roll(randomizer: Randomizer.new)
  38. 10 parse()
  39. 10 index = roll_index(randomizer)
  40. 10 else: 10 then: 0 unless valid? && index
  41. return nil
  42. end
  43. 10 key = "#{index}:"
  44. 109 row = @rows.find { |l| l.start_with?(key) }
  45. 10 else: 10 then: 0 unless row
  46. return nil
  47. end
  48. 10 chosen = row.delete_prefix(key).gsub('\n', "\n").strip
  49. 10 Result.new.tap do |r|
  50. 10 r.text = "#{@name}(#{index}) > #{chosen}"
  51. 10 r.rands = randomizer.rand_results
  52. 10 r.detailed_rands = randomizer.detailed_rand_results
  53. end
  54. end
  55. # 有効なダイス表かをチェックする。テキスト形式のミスだけではなく、抜けている出目や範囲外の出目がないか確認する。
  56. # @return [Boolean]
  57. 1 def valid?
  58. 21 parse()
  59. 373 has_index = @rows.all? { |row| /^\d+:/.match?(row) }
  60. 21 else: 21 then: 0 unless has_index
  61. return false
  62. end
  63. 21 index_list = @rows.map(&:to_i).uniq.sort
  64. 21 case @type
  65. when: 8 when /^\d+D\d+$/
  66. 8 valid_d?(index_list)
  67. when: 4 when "D66", "D66N"
  68. 4 valid_d66?(index_list)
  69. when: 4 when "D66A", "D66S"
  70. 4 valid_d66_asc_sort?(index_list)
  71. when: 4 when "D66D"
  72. 4 valid_d66_desc_sort?(index_list)
  73. else: 1 else
  74. 1 false
  75. end
  76. end
  77. 1 private
  78. # @return [Integer, nil]
  79. 1 def roll_index(randomizer)
  80. 10 then: 4 else: 6 if (m = /^(\d+)D(\d+)$/.match(@type))
  81. 4 times = m[1].to_i
  82. 4 sides = m[2].to_i
  83. 4 return randomizer.roll_sum(times, sides)
  84. end
  85. 6 else: 0 case @type
  86. when: 2 when "D66", "D66N"
  87. 2 randomizer.roll_d66(D66SortType::NO_SORT)
  88. when: 2 when "D66A", "D66S"
  89. 2 randomizer.roll_d66(D66SortType::ASC)
  90. when: 2 when "D66D"
  91. 2 randomizer.roll_d66(D66SortType::DESC)
  92. end
  93. end
  94. 1 def parse
  95. 31 then: 10 else: 21 return if @rows
  96. 21 lines = @text.split(/\R/).map(&:rstrip).reject(&:empty?)
  97. 21 @name = lines.shift
  98. 21 @type = lines.shift.upcase
  99. 21 @rows = lines
  100. end
  101. 1 def valid_d?(index_list)
  102. 8 m = /^(\d+)D(\d+)$/.match(@type)
  103. 8 times = m[1].to_i
  104. 8 sides = m[2].to_i
  105. 8 expected_size = times * sides - times + 1
  106. 8 then: 2 else: 6 if index_list.size != expected_size
  107. 2 return false
  108. end
  109. 6 return index_list.first == times && index_list.last == times * sides
  110. end
  111. 1 def valid_d66?(index_list)
  112. 4 then: 1 else: 3 if index_list.size != 36
  113. 1 return false
  114. end
  115. 3 expected_index = (1..6).map do |tens|
  116. 126 (1..6).map { |ones| tens * 10 + ones }
  117. end.flatten
  118. 3 return index_list == expected_index
  119. end
  120. 1 def valid_d66_asc_sort?(index_list)
  121. 4 then: 0 else: 4 if index_list.size != 21
  122. return false
  123. end
  124. 4 expected_index = (1..6).map do |tens|
  125. 108 (tens..6).map { |ones| tens * 10 + ones }
  126. end.flatten
  127. 4 return index_list == expected_index
  128. end
  129. 1 def valid_d66_desc_sort?(index_list)
  130. 4 then: 0 else: 4 if index_list.size != 21
  131. return false
  132. end
  133. 4 expected_index = (1..6).map do |ones|
  134. 108 (ones..6).map { |tens| tens * 10 + ones }
  135. end.flatten.sort
  136. 4 return index_list == expected_index
  137. end
  138. end
  139. end